如何使用Java Reflections扫描查找多层级注解标记的类
问题说明
尝试一次性获取所有被多层级注解标记的类,以如下代码为例:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Controller public @interface HttpController { } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Controller public @interface ConsoleController { } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Controller { } @Controller public class TestOne { } @HttpController public class TestTwo { } @ConsoleController public class TestThree { } public class Demo { public static void main(String[] args) { Reflections reflections = new Reflections( new ConfigurationBuilder() .setUrls( ClasspathHelper.forPackage( Demo.class.getPackageName())) .setScanners(new SubTypesScanner(false), new TypeAnnotationsScanner()) .filterInputsBy(it -> it.startsWith(Demo.class.getPackageName()))); reflections.getTypesAnnotatedWith(Controller.class).forEach(clazz -> System.out.print(clazz.getSimpleName() + " ") ); } }
运行上述代码时,默认仅能输出TestOne。预期效果是无需额外硬编码判断,即可输出TestOne TestTwo TestThree;后续新增如下代码时,不需要修改反射扫描逻辑就能自动识别对应的标记类:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Controller public @interface AnotherController{ } @AnotherController public class TestFour{ }
实现方案
默认调用getTypesAnnotatedWith仅传入注解类型参数时,只会匹配类上直接声明的注解,不会递归遍历注解上标注的元注解,因此无法识别被@HttpController、@ConsoleController这类标记了@Controller元注解的自定义注解修饰的类。
只需要修改getTypesAnnotatedWith的调用逻辑,传入第二个参数开启元注解递归匹配即可:
// 第二个参数true表示开启任意深度的元注解匹配 reflections.getTypesAnnotatedWith(Controller.class, true).forEach(clazz -> System.out.print(clazz.getSimpleName() + " ") );
修改后初始场景运行即可正确输出TestOne TestTwo TestThree,后续新增带@Controller元注解的自定义注解、以及被该注解修饰的类时,不需要调整任何扫描配置,会自动被识别纳入结果,新增TestFour后输出结果为TestOne TestTwo TestThree TestFour。
注:原示例代码中forEach内的变量名使用了Java关键字
class,会导致编译错误,需要替换为clazz这类合法变量名。
内容的提问来源于stack exchange,提问作者DanielDeboeverie
相关产品推荐
相关产品推荐

