java通过反射找到指定接口的实现类
方法1
如果所有实现类都交给spring容器管理,则可以使用spring的getBeansOfType获取所有相关属性的实现类,
用法如下:
//applicationContext通过ApplicationAware自动注入
//key位 beanName,value为bean
Map<String, Interface> result = applicationContext.getBeansOfType(Interface.class);
//返回 beanName 的String 数组
String[] result = applicationContext.getBeanNamesForType(Interface.class);
方法2
因为Spring的方法会遍历搜索所有的实例来判断找出其实现类,而我个人是打算把算法的接口和具体实现都方在同一个包里,没打算放其他地方,所以完全没有必要循环遍历所有的实例,还有一些美中不足
参考文章:java最全的获取某个接口或者某个类所有对应的所有实现类和继承类的工具类--反射动态获取、非动态获取、按照路径获取等总结
这篇博客的大致思路是:
(1)获取当前线程的ClassLoader对象
(2)根据ClassLoader获取目录对象,并对目录里的文件进行遍历
(3)过滤出.class为结尾的文件,并加载到Vector中
(4)然后对Vector中的类进行判断是不是指定接口的实现类
(5)返回所有符合的类
这篇文章给出了两种实现方式,但是还是有不足支持,这篇文章只能在自己本地测试运行使用,无法应用线上,项目发到线上代码打包成jar包后,这种方式就无法使用了
第二篇文章:获取全部子类或接口的全部实现
这一篇博客给出了两种方式,并同时给出了jar包的处理方法,用到了JarFile工具类,并且实现了全路径的搜索。
完整流程图:
代码如下:
package utils;
import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ClassUtils {
/*
* 获取指定接口的所有实现实例
*/
public static List<Object> getAllObjectByInterface(Class<?> c)
throws InstantiationException, IllegalAccessException {
List<Object> list = new ArrayList<Object>();
List<Class<?>> classes = getAllClassByInterface(c);
for (int i = 0; i < classes.size(); i++) {
list.add(classes.get(i).newInstance());
}
return list;
}
/*
* 获取指定接口的实例的Class对象
*/
public static List<Class<?>> getAllClassByInterface(Class<?> c) {
// 如果传入的参数不是接口直接结束
if (!c.isInterface()) {
return null;
}
// 获取当前包名
String packageName = c.getPackage().getName();
List<Class<?>> allClass = null;
try {
allClass = getAllClassFromPackage(packageName);
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
ArrayList<Class<?>> list = new ArrayList<Class<?>>();
for (int i = 0; i < allClass.size(); i++) {
if (c.isAssignableFrom(allClass.get(i))) {
if (!c.equals(allClass.get(i))) {
list.add(allClass.get(i));
}
}
}
return list;
}
private static List<Class<?>> getAllClassFromPackage(String packageName) throws IOException, ClassNotFoundException{
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String path = packageName.replace(".", "/");
Enumeration<URL> enumeration = classLoader.getResources(path);
List<String> classNames = getClassNames(enumeration, packageName);
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
for (int i = 0; i < classNames.size(); i++) {
classes.add(Class.forName(classNames.get(i)));
}
return classes;
}
public static List<String> getClassNames(Enumeration<URL> enumeration, String packageName) {
List<String> classNames = null;
while (enumeration.hasMoreElements()) {
URL url = enumeration.nextElement();
if (url != null) {
String type = url.getProtocol();
if (type.equals("file")) {
System.out.println("type : file");
String fileSearchPath = url.getPath();
if(fileSearchPath.contains("META-INF")) {
System.out.println("continue + " + fileSearchPath);
continue;
}
classNames = getClassNameByFile(fileSearchPath);
} else if (type.equals("jar")) {
try {
System.out.println("type : jar");
JarURLConnection jarURLConnection = (JarURLConnection)url.openConnection();
JarFile jarFile = jarURLConnection.getJarFile();
classNames = getClassNameByJar(jarFile, packageName);
} catch (IOException e) {
e.printStackTrace();
}
} else {
System.out.println("type : none");
}
}
}
return classNames;
}
/*
* 获取项目某路径下的所有类
*/
public static List<String> getClassNameByFile(String fileSearchPath) {
List<String> classNames = new ArrayList<String>();
File file = new File(fileSearchPath);
File[] childFiles = file.listFiles();
for(File childFile : childFiles) {
if(childFile.isDirectory()) {
classNames.addAll(getClassNameByFile(childFile.getPath()));
} else {
String childFilePath = childFile.getPath();
if (childFilePath.endsWith(".class")) {
String className = childFilePath.substring(childFilePath.lastIndexOf("\\bin\\") + 1,
childFilePath.length()).replaceAll("\\\\", ".");
className = className.substring(4, className.indexOf(".class"));
classNames.add(className);
}
}
}
return classNames;
}
/*
* 从jar包中获取某路径下的所有类
*/
public static List<String> getClassNameByJar(JarFile jarFile, String packageName) {
List<String> classNames = new ArrayList<String>();
Enumeration<JarEntry> entrys = jarFile.entries();
while (entrys.hasMoreElements()) {
JarEntry jarEntry = (JarEntry) entrys.nextElement();
String entryName = jarEntry.getName();
if(entryName.endsWith(".class")) {
String className = entryName.replace("/", ".");
className = className.substring(0, className.indexOf(".class"));
classNames.add(className);
}
}
return classNames;
}
}
通过反射获取泛型参数类型
/**
* 获取指定类的泛型类型, 只获取第一个泛型类型
*
* @param clazz
* 泛型类
*
* @return 泛型类型
*/
public static Class<?> getClassFirstGenericsParam(Class<?> clazz) {
Type genericSuperclass = clazz.getGenericSuperclass();
Type actualTypeArgument = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
return (Class<?>) actualTypeArgument;
}
评论区