Escaneo de anotaciones Java en tiempo de ejecución

¿Cuál es la mejor forma de buscar toda la ruta de clase para una clase anotada?

Estoy haciendo una biblioteca y quiero permitir que los usuarios anoten sus clases, así que cuando la aplicación web se inicie necesito escanear toda la ruta de clases para obtener cierta anotación.

¿Conoces una biblioteca o una instalación de Java para hacer esto?

Editar: estoy pensando en algo así como la nueva funcionalidad para Java EE 5 Web Services o EJB. @WebService su clase con @WebService o @EJB y el sistema encuentra estas clases durante la carga para que se @EJB acceder de forma remota.

Use org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider

API

Un proveedor de componentes que escanea el classpath desde un paquete base. Luego aplica exclusión e incluye filtros en las clases resultantes para encontrar candidatos.

 ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(); scanner.addIncludeFilter(new AnnotationTypeFilter(.class)); for (BeanDefinition bd : scanner.findCandidateComponents()) System.out.println(bd.getBeanClassName()); 

Y otra solución son los reflections de Google .

Revisión rápida:

  • La solución Spring es el camino a seguir si está usando Spring. De lo contrario, es una gran dependencia.
  • Usar ASM directamente es un poco engorroso.
  • Usar Java Assist directamente también es torpe.
  • La anulación es súper liviana y conveniente. No hay integración de maven todavía.
  • Las reflexiones de Google atraen colecciones de Google. Indexa todo y luego es súper rápido.

(Editar: FastClasspathScanner ahora ha sido renombrado a ClassGraph)

Prueba ClassGraph . (Descargo de responsabilidad, yo soy el autor). ClassGraph admite el análisis de anotaciones, tanto en tiempo de ejecución como en tiempo de comstackción, pero también mucho más. ClassGraph puede construir una representación abstracta de todo el gráfico de clase (todas las clases, anotaciones, métodos, parámetros de método y campos) en memoria, para todas las clases en el classpath o para las clases en paquetes incluidos en la lista blanca, y puede consultar ese gráfico de clase sin embargo usted quiere. ClassGraph admite más mecanismos de especificación y classloaders de classpath que cualquier otro escáner, y también funciona a la perfección con el nuevo sistema de módulos JPMS, por lo que si basa su código en ClassGraph, su código será totalmente portátil. Vea la API aquí.

Si desea una solución muy ligera (sin dependencias, API simple, archivo jar de 15 kb) y muy rápida , eche un vistazo al annotation-detector encuentra en https://github.com/rmuller/infomas-asl

Descargo de responsabilidad: soy el autor.

Puede usar Java Pluggable Annotation Processing API para escribir el procesador de anotaciones que se ejecutará durante el proceso de comstackción y recostackrá todas las clases anotadas y comstackrá el archivo de índice para su uso en tiempo de ejecución.

Esta es la manera más rápida posible de hacer un descubrimiento de clase anotado porque no necesita escanear su ruta de clase en tiempo de ejecución, que generalmente es una operación muy lenta. Además, este enfoque funciona con cualquier cargador de clases y no solo con URLClassLoaders generalmente soportados por escáneres de tiempo de ejecución.

El mecanismo anterior ya está implementado en la biblioteca ClassIndex .

Para usarlo, anota tu anotación personalizada con @IndexAnnotated meta-anotación. Esto creará en tiempo de comstackción un archivo de índice: META-INF / annotations / com / test / YourCustomAnnotation que enumera todas las clases anotadas. Puede acceder al índice en tiempo de ejecución ejecutando:

 ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class) 

Use el ServiceLoader o implemente el suyo si no está en Java 6.

Quizás un procesador de anotaciones pueda producir los archivos necesarios en META-INF / services en tiempo de comstackción.

Prueba Scannotation .

Se puede usar para buscar el classpath o el directorio lib de su aplicación web para anotaciones específicas.

Es posible que desee utilizar http://code.google.com/p/annovention/

Ligeramente offtopic, pero Spring también hace algo similar, usando , ¿de qué podrías estudiar el código fuente?

Spring proporciona la capacidad de detectar automáticamente clases ‘estereotipadas’ […]. Para autodetectar estas clases y registrar los beans correspondientes, se requiere la inclusión de [context: component-scan element].

Con Spring también puede escribir lo siguiente utilizando la clase AnnotationUtils. es decir:

 Class clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null); 

Para obtener más detalles y todos los métodos diferentes, consulte los documentos oficiales: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html

No estoy seguro de si te ayudará o no, pero podrías mirar el proyecto de descubrimiento de apache commons.

proyecto de descubrimiento

¿Es demasiado tarde para responder? Yo diría que es mejor recurrir a Bibliotecas como ClassPathScanningCandidateComponentProvider o como Scannotations

Pero incluso después de que alguien quiere probarlo con classLoader, he escrito algunos por mi cuenta para imprimir las anotaciones de las clases en un paquete:

 public class ElementScanner { public void scanElements(){ try { //Get the package name from configuration file String packageName = readConfig(); //Load the classLoader which loads this class. ClassLoader classLoader = getClass().getClassLoader(); //Change the package structure to directory structure String packagePath = packageName.replace('.', '/'); URL urls = classLoader.getResource(packagePath); //Get all the class files in the specified URL Path. File folder = new File(urls.getPath()); File[] classes = folder.listFiles(); int size = classes.length; List> classList = new ArrayList>(); for(int i=0;i repoClass; repoClass = Class.forName(classNamePath); Annotation[] annotations = repoClass.getAnnotations(); for(int j =0;j 

Y en el archivo de configuración, pones el nombre del paquete y lo desmarcas en una clase.

Java no tiene “Discovery”. La única forma que conozco es escanear el directorio en el que deberían estar los archivos .class, analizar los nombres y usar eso. Horriblemente feo, tal vez hay un paquete mejor en estos días, no lo he visto en unos años.

Por lo general, este problema solía abordarse al incluir un archivo de propiedades o un archivo .xml con los nombres de clase en él.

También estaría interesado en escuchar una mejor respuesta.

La API de Classloader no tiene un método de “enumerar”, porque la carga de clases es una actividad “a petición”: generalmente tienes miles de clases en tu ruta de clase, de las cuales solo se necesitará una fracción (el rt.jar solo es 48MB hoy en día!).

Entonces, incluso si pudiera enumerar todas las clases, esto consumiría mucho tiempo y memoria.

El enfoque simple es hacer una lista de las clases afectadas en un archivo de instalación (xml o lo que sea que se ajuste a su fantasía); si desea hacer esto automáticamente, restrinja a un JAR o directorio de una clase.

Google Reflections parece ser mucho más rápido que Spring. Encontré esta solicitud de función que hace referencia a esta diferencia: http://www.opensaga.org/jira/browse/OS-738

Esta es una razón para usar Reflections ya que el tiempo de inicio de mi aplicación es realmente importante durante el desarrollo. Las reflexiones también parecen ser muy fáciles de usar para mi caso de uso (encuentre todos los implementadores de una interfaz).

Si está buscando una alternativa a los reflections, me gustaría recomendar Panda Utilities – AnnotationsScanner . Es un escáner libre de guayaba (Guava tiene ~ 3MB, Panda Utilities tiene ~ 200kb) basado en el código fuente de la biblioteca de reflections.

También está dedicado para búsquedas basadas en el futuro. Si desea escanear varias veces las fonts incluidas o incluso proporcionar una API, que permite que alguien escanee la ruta de ClassFiles actual, AnnotationsScannerProcess almacena en caché todos los ClassFiles recuperados, por lo que es muy rápido.

Ejemplo simple de uso de AnnotationsScanner :

 AnnotationsScanner scanner = AnnotationsScanner.createScanner() .includeSources(ExampleApplication.class) .build(); AnnotationsScannerProcess process = scanner.createWorker() .addDefaultProjectFilters("net.dzikoysk") .fetch(); Set> classes = process.createSelector() .selectTypesAnnotatedWith(AnnotationTest.class); 

Si desea una biblioteca de Scala, use Sclasner: https://github.com/ngocdaothanh/sclasner

Intereting Posts