¿Cuál es la mejor manera de buscar en todo el classpath una clase anotada?
Estoy haciendo una biblioteca y quiero permitir que los usuarios anoten sus clases, por lo que cuando se inicia la aplicación web, necesito escanear toda la ruta de clase para obtener cierta anotación.
¿Conoces una biblioteca o una instalación de Java para hacer esto?
Editar: Estoy pensando en algo como la nueva funcionalidad para Java EE 5 Web Services o EJB's. Anota tu clase con @WebService
o @EJB
y el sistema encuentra estas clases mientras se carga para que sean accesibles de forma remota.
fuente
@Conditional
anotaciones. Entonces, si una clase tiene un@Conditional
valor que devuelve falso, no será devueltofindCandidateComponents
, incluso si coincide con el filtro del escáner. Esto me sorprendió hoy: terminé usando la solución de Jonathan a continuación.BeanDefinition
objeto no proporciona una forma de obtener la clase directamente. Lo más parecido parece sergetBeanClassName
que devuelve un nombre de clase totalmente calificado, pero el comportamiento exacto de este método no está claro. Además, no está claro en qué cargador de clases se encontró la clase.Class<?> cl = Class.forName(beanDef.getBeanClassName());
farenda.com/spring/find-annotated-classesY otra solución son las reflexiones de Google .
Revisión rápida:
fuente
new Reflections("my.package").getTypesAnnotatedWith(MyAnnotation.class)
. c'est tout.Puede encontrar clases con cualquier anotación dada con ClassGraph , así como buscar otros criterios de interés, por ejemplo, clases que implementan una interfaz determinada. (Descargo de responsabilidad, soy el autor de ClassGraph.) ClassGraph puede construir una representación abstracta de todo el gráfico de clase (todas las clases, anotaciones, métodos, parámetros de métodos y campos) en la memoria, para todas las clases en el classpath, o para las clases en paquetes en la lista blanca, y puede consultar ese gráfico de clase como desee. ClassGraph admite más mecanismos de especificación de classpath y cargadores de clases 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á máximamente portátil. Vea la API aquí.
fuente
Reflections
. Además, si está usando guayaba / etc. y desea cambiar las colecciones, es fácil. Grandes comentarios en el interior también.Si desea un peso realmente ligero (sin dependencias, API simple, archivo jar de 15 kb) y una solución muy rápida , eche un vistazo
annotation-detector
a https://github.com/rmuller/infomas-aslDescargo de responsabilidad: soy el autor.
fuente
Puede usar la API de procesamiento de anotación conectable de Java para escribir un procesador de anotación que se ejecutará durante el proceso de compilación y recopilará todas las clases anotadas y creará el archivo de índice para el uso en tiempo de ejecución.
Esta es la forma más rápida posible de hacer un descubrimiento de clase anotado porque no necesita escanear su classpath 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 compatibles con escáneres de tiempo de ejecución.
El mecanismo anterior ya está implementado en la biblioteca ClassIndex .
Para usarlo, anote su anotación personalizada con @IndexAnotaciones anotadas . Esto creará en tiempo de compilació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:
fuente
¿Es demasiado tarde para responder? Yo diría que es mejor ir por bibliotecas como ClassPathScanningCandidateComponentProvider o como Scannotations
Pero incluso después de que alguien quiera probarlo con classLoader, he escrito algunos por mi cuenta para imprimir las anotaciones de las clases en un paquete:
Y en el archivo de configuración, coloca el nombre del paquete y lo desmarca a una clase.
fuente
Con Spring también puede escribir lo siguiente usando la clase AnnotationUtils. es decir:
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
fuente
null
valor como el segundo parámetro (que define la clase, en la cual la jerarquía de herencia Spring buscará una clase que use la Anotación), siempre obtendrá unnull
retorno, de acuerdo con la implementación.Hay un comentario maravilloso de zapp que incluye todas esas respuestas:
fuente
La API de Classloader no tiene un método de "enumeración", porque la carga de clases es una actividad "a pedido": generalmente tiene miles de clases en su classpath, de las cuales solo se necesitará una fracción (rt.jar ¡solo 48MB hoy en día!).
Entonces, incluso si pudieras enumerar todas las clases, esto consumiría mucho tiempo y memoria.
El enfoque simple es enumerar las clases en cuestión en un archivo de configuración (xml o lo que más le convenga); Si desea hacer esto automáticamente, limítese a un JAR o un directorio de clase.
fuente
Reflexión de Google si también quieres descubrir interfaces.
Spring
ClassPathScanningCandidateComponentProvider
no está descubriendo interfaces.fuente
Google Reflections parece ser mucho más rápido que Spring. Encontré esta solicitud de función que aborda 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. Reflexiones también parece ser muy fácil de usar para mi caso de uso (encontrar todos los implementadores de una interfaz).
fuente
Si está buscando una alternativa a las reflexiones, me gustaría recomendar Panda Utilities - AnnotationsScanner . Es un escáner libre de guayaba (guayaba tiene ~ 3 MB, Panda Utilities tiene ~ 200 kb) basado en el código fuente de la biblioteca de reflexiones.
También está dedicado a búsquedas futuras. Si desea escanear varias veces las fuentes incluidas o incluso proporcionar una API, que permite a alguien escanear la ruta de clase actual,
AnnotationsScannerProcess
almacena en caché todas las recuperadasClassFiles
, por lo que es realmente rápido.Ejemplo simple de
AnnotationsScanner
uso:fuente
La primavera tiene algo llamado
AnnotatedTypeScanner
clase.Esta clase usa internamente
Esta clase tiene el código para el escaneo real de los recursos de classpath . Para ello, utiliza los metadatos de clase disponibles en tiempo de ejecución.
Simplemente se puede extender esta clase o usar la misma clase para escanear. A continuación se muestra la definición del constructor.
fuente