如何在注解处理器中获取所有实现指定接口的类?
在注解处理器中获取所有实现指定接口的类并生成Map
核心思路:基于编译期扫描与代码生成
注解处理器运行在编译阶段,可直接获取当前编译上下文内的所有类元素,结合SPI式的资源收集处理跨模块依赖类,最终直接生成Map的初始化代码(避免运行时反射开销)。
编译期扫描当前上下文的实现类
通过ProcessingEnvironment提供的工具类,遍历所有编译中的TypeElement,判断是否实现目标接口:// 获取目标接口的TypeElement TypeElement targetInterface = processingEnv.getElementUtils().getTypeElement("com.your.package.TargetInterface"); TypeMirror targetType = targetInterface.asType(); Types typeUtils = processingEnv.getTypeUtils(); // 遍历所有根元素(可通过RoundEnvironment获取) for (Element element : roundEnv.getRootElements()) { if (element.getKind() == ElementKind.CLASS) { TypeElement classElement = (TypeElement) element; // 判断当前类是否实现了目标接口 if (typeUtils.isAssignable(classElement.asType(), targetType)) { // 记录该类的全限定名 String className = classElement.getQualifiedName().toString(); } } }处理依赖jar包中的实现类
若目标类在依赖模块或jar中,编译期无法直接扫描,可通过SPI机制收集:- 在每个模块的注解处理器中,将发现的实现类全限定名写入
META-INF/services/com.your.package.TargetInterface文件。 - 最终生成Map时,读取所有该路径下的文件,收集所有实现类名。
- 在每个模块的注解处理器中,将发现的实现类全限定名写入
直接生成Map初始化代码
推荐在编译期生成Map的Java代码,无需运行时反射:
利用Filer创建新的Java类,写入Map初始化逻辑:// 创建生成类的文件对象 JavaFileObject file = processingEnv.getFiler().createSourceFile("com.your.package.GeneratedMapHolder"); try (Writer writer = file.openWriter()) { writer.write("package com.your.package;\n"); writer.write("import java.util.HashMap;\n"); writer.write("import java.util.Map;\n"); writer.write("public class GeneratedMapHolder {\n"); writer.write(" public static final Map<Class<?>, Object> IMPLEMENT_MAP = new HashMap<>();\n"); writer.write(" static {\n"); // 遍历收集到的实现类,逐个添加到Map中 for (String className : collectedClassNames) { writer.write(String.format(" IMPLEMENT_MAP.put(%s.class, new %s());\n", className, className)); } writer.write(" }\n"); writer.write("}\n"); }关键注意事项
- 必须在
META-INF/services/javax.annotation.processing.Processor文件中注册你的注解处理器类,确保编译时被调用。 - 若处理Kotlin类,需配合KAPT工具,确保能正确识别Kotlin类元素。
- 通过
@SupportedAnnotationTypes指定处理器关注的注解,缩小扫描范围提升性能。
- 必须在
内容的提问来源于stack exchange,提问作者kylie.zoltan
相关产品推荐
相关产品推荐

