纯原生Java实现:获取整个项目中指定接口所有的实现类

不使用第三方,不使用属性文件,不指定包名,获取整个系统中某一个接口所有的实现类,纯Java实现

java 复制代码
/**
 * 类查找器,用于扫描类路径中的所有类,并找出指定类的实现类。
 * 该类通过递归扫描类路径下的所有 .class 文件,加载并判断是否为目标类的实现类。
 */
public class ClassFinder {
    /**
     * 获取指定类的所有实现类(非接口本身)。
     * 从类路径根目录开始扫描,使用当前线程的类加载器获取资源路径。
     *
     * @param clazz 要查找实现类的目标类(通常是抽象类或接口)
     * @return 返回目标类的所有实现类组成的列表
     */
    public static List<Class<?>> getImplementationsOfMyService(Class<?> clazz) {
        List<Class<?>> implementations = new ArrayList<>();
        // 设置为空字符串表示从类路径根开始扫描
        String packageName = "";

        // 使用当前线程的类加载器加载类资源
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Enumeration<URL> resources = null;
        try {
            // 获取类路径下对应包名的资源路径(转换为文件系统路径格式)
            resources = classLoader.getResources(packageName.replace('.', '/'));
            while (resources.hasMoreElements()) {
                URL resource = resources.nextElement();
                File file = new File(resource.getFile());
                // 开始递归扫描该目录下的类文件
                scanDirectory(clazz, file, "", implementations);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return implementations;
    }

    /**
     * 递归扫描目录及其子目录中的类文件。
     * 对每个类文件进行加载并判断是否是目标类的实现类。
     *
     * @param clazz 目标类(要查找其实现类)
     * @param dir 当前扫描的目录
     * @param pkg 当前目录对应的包名前缀
     * @param list 存储符合条件的实现类
     */
    private static void scanDirectory(Class<?> clazz, File dir, String pkg, List<Class<?>> list) {
        if (!dir.exists()) return;

        for (File file : Objects.requireNonNull(dir.listFiles())) {
            if (file.isDirectory()) {
                // 如果是目录,递归进入子目录继续扫描
                scanDirectory(clazz, file, pkg + file.getName() + ".", list);
            } else if (file.getName().endsWith(".class")) {
                // 构建完整的类名(包含包名)
                String className = pkg + file.getName().replace(".class", "");
                try {
                    // 加载类
                    Class<?> tmp = Class.forName(className);
                    // 判断是否为目标类的实现类,并排除接口类型
                    if (clazz.isAssignableFrom(tmp) && !tmp.isInterface()) {
                        list.add(tmp);
                    }
                } catch (Exception ignored) {
                    // 忽略加载失败的类
                }
            }
        }
    }

    // 测试入口:演示如何使用ClassFinder查找AnnotationHandler接口的实现类
    public static void main(String[] args) throws Exception {
        // 查找AnnotationHandler接口的所有实现类
        List<Class<?>> classes = getImplementationsOfMyService(AnnotationHandler.class);
        System.out.println("找到以下实现类:");
        for (Class<?> c : classes) {
            System.out.println(c.getName());
        }
    }
}
相关推荐
今天也是元气满满的一天呢17 分钟前
java学习之数据结构:一、数组
java·数据结构·学习
heyCHEEMS1 小时前
最大子段和 Java
java·开发语言·算法
-曾牛2 小时前
探索 Spring AI 的 ChatClient API:构建智能对话应用的利器
java·人工智能·spring boot·后端·spring·springai·ai指南
白露与泡影2 小时前
使用OAuth2保护Spring AI MCP服务!
java·后端·spring
magic 2452 小时前
Spring 命名空间注入:p、c 与 .util 的深度解析
java·前端·spring
橘猫云计算机设计2 小时前
基于springboot的金院银行厅预约系统的设计及实现(源码+lw+部署文档+讲解),源码可白嫖!
java·数据库·spring boot·后端·爬虫·spring·毕业设计
Aurora_NeAr3 小时前
Spring IoC容器的设计与实现
java·后端·spring
5173 小时前
pymysql
java·数据库·oracle
八股文领域大手子3 小时前
单机 vs 分布式:Java 后端限流的选择题
java·开发语言·数据结构·算法·spring
娃哈哈哈哈呀3 小时前
组件通信-v-model
java·服务器·前端