Java 获得指定包名下接口类的所有实现类
说明
使用目录扫描和Java反射的方法获得指定包名下接口类的所有实现类,不同于SPI需要指定实现类的完整包路径,也不同于 Spring IOC 需要使用注解或配置去扫描实现类。
实现
package cn.chenyuning.utils;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.HashSet;
import java.util.Set;
public class ClassUtils {
private static final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
/**
* @Description: 获取指定包名下接口的实现类
* @Param: [clazz, packageName]
* @return: java.util.Set<java.lang.Class<?>>
* @Author: Dr.Chan
* @Date: 2021/12/27 17:42
*/
public static Set<Class<?>> getSubClass(Class clazz, String packageName) {
Set<Class<?>> subClass = new HashSet<>();
if(!clazz.isInterface()) return subClass;
if(packageName == null) {
packageName = clazz.getPackage().getName();
}
try {
Set<Class<?>> classSet = findClass(toAbsolutePath(packageName));
classSet.forEach(item -> {
if(clazz.isAssignableFrom(item) && !clazz.equals(item)) {
subClass.add(item);
}
});
} catch (Exception e) {
e.printStackTrace();
}
return subClass;
}
/**
* @Description: 获取相同包下接口的实现类
* @Param: [clazz]
* @return: java.util.Set<java.lang.Class<?>>
* @Author: Dr.Chan
* @Date: 2021/12/27 17:43
*/
public static Set<Class<?>> getSubClass(Class clazz) {
return getSubClass(clazz, null);
}
private static String toAbsolutePath(String packageName) {
String packagePath = packageName.replace(".", "/");
return new File(classLoader.getResource("").getPath() + packagePath).getAbsolutePath();
}
private static Set<Class<?>> findClass(String path) throws UnsupportedEncodingException, ClassNotFoundException {
Set<Class<?>> classSet = new HashSet<>();
File dir = new File(path);
if (!dir.exists()) return classSet;
File baseDir = new File(classLoader.getResource("").getPath());
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
classSet.addAll(findClass(file.getAbsolutePath()));
}
if (file.getName().endsWith(".class")) {
classSet.add(Class.forName(
path.replace(baseDir.getAbsolutePath(), "").replaceFirst("^(.)", "").replace(File.separator, ".") + "." +
file.getName().replace(".class", "")
));
}
}
return classSet;
}
}