Herramientas para encontrar clases anotadas en Java

Este artículo proporciona una breve descripción de tres herramientas para encontrar clases anotadas en un proyecto de Java.


imagen


Gatos de entrenamiento
@Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation {} @MyAnnotation public class Bar {} @MyAnnotation public class Foo {} 

Primavera


En primavera, ClassPathScanningCandidateComponentProvider sirve para este propósito.


Característica: se arrastra a ClassPath, buscando clases que satisfagan las condiciones dadas

Características adicionales

tiene muchos otros filtros (por tipo, por métodos, etc.)


Ejemplo


 @Benchmark public void spring() { ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); scanner.addIncludeFilter(new AnnotationTypeFilter(MyAnnotation.class)); List<String> collect = scanner .findCandidateComponents("edu.pqdn.scanner") .stream() .map(BeanDefinition::getBeanClassName) .filter(Objects::nonNull) .collect(Collectors.toList()); assertEquals(collect.size(), 2); assertTrue(collect.contains("edu.pqdn.scanner.test.Bar")); assertTrue(collect.contains("edu.pqdn.scanner.test.Foo")); } 

Reflexiones


Característica: se arrastra a ClassPath, buscando clases que satisfagan las condiciones dadas

Características adicionales
  • obtener todos los subtipos de algún tipo
  • obtener todos los tipos / miembros anotados con alguna anotación
  • obtener todos los recursos que coincidan con una expresión regular
  • Obtenga todos los métodos con firma específica, incluidos parámetros, anotaciones de parámetros y tipo de retorno

dependencia
 <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.11</version> </dependency> 

Ejemplo


 @Benchmark public void reflection() { Reflections reflections = new Reflections("edu.pqdn.scanner"); Set<Class<?>> set = reflections.getTypesAnnotatedWith(MyAnnotation.class); List<String> collect = set.stream() .map(Class::getCanonicalName) .collect(Collectors.toList()); assertEquals(collect.size(), 2); assertTrue(collect.contains("edu.pqdn.scanner.test.Bar")); assertTrue(collect.contains("edu.pqdn.scanner.test.Foo")); } 

índice de clase


Característica: NO entra en ClassPath, en cambio, las clases se indexan en tiempo de compilación

dependencia
 <dependency> <groupId>org.atteo.classindex</groupId> <artifactId>classindex</artifactId> <version>3.4</version> </dependency> 

Gatos de entrenamiento
 @IndexMyAnnotated public @interface IndexerAnnotation {} @IndexerMyAnnotation public class Bar {} @IndexerMyAnnotation public class Foo {} 

Ejemplo


 @Benchmark public void indexer() { Iterable<Class<?>> iterable = ClassIndex.getAnnotated(IndexerMyAnnotation.class); List<String> list = StreamSupport.stream(iterable.spliterator(), false) .map(aClass -> aClass.getCanonicalName()) .collect(Collectors.toList()); assertEquals(list.size(), 2); assertTrue(list.contains("edu.pqdn.scanner.classindexer.test.Bar")); assertTrue(list.contains("edu.pqdn.scanner.classindexer.test.Foo")); } 

Jmh


 Benchmark Mode Cnt Score Error Units ScannerBenchmark.indexer avgt 50 0,100 ? 0,001 ms/op ScannerBenchmark.reflection avgt 50 5,157 ? 0,047 ms/op ScannerBenchmark.spring avgt 50 4,706 ? 0,294 ms/op 

Conclusión


Como puede ver, el indexador es la herramienta más productiva, sin embargo, las anotaciones utilizadas para buscar deben tener el estereotipo @IndexAnnotated.


Las otras dos herramientas funcionan mucho más lentamente, pero para su trabajo no se necesita chamanismo con el código. La desventaja se nivela completamente si la búsqueda es necesaria solo al inicio de la aplicación

Source: https://habr.com/ru/post/es424511/


All Articles