Red de conocimiento informático - Conocimiento sistemático - Comprensión profunda del mecanismo de anotación Spring: síntesis de anotaciones combinadas

Comprensión profunda del mecanismo de anotación Spring: síntesis de anotaciones combinadas

Como todos sabemos, Spring ha admitido el uso de anotaciones para reemplazar la engorrosa configuración xml desde la versión 2.5, y la configuración anotada se ha adoptado por completo en Springboot. En el uso diario, si hace clic en algunas anotaciones de uso común, encontrará que siempre hay otras anotaciones en una anotación, como @Service:

En la mayoría de los casos, podemos equiparar la anotación @Service con anotación @Component, porque Spring extiende el mecanismo de metaanotación basado en su JDK.

En Java, las metaanotaciones son anotaciones que se pueden anotar encima de otras anotaciones. En primavera, al extender este mecanismo, se implementarán algunas funciones no admitidas por el JDK nativo, como permitir que dos propiedades sean alias en las anotaciones, o tratar directamente una subanotación con una metaanotación como una metaanotación, o basada en en esto, anule el valor de la metaanotación con el valor de la subanotación a través de @AliasFor o la estrategia homónima.

Basado en la rama 5.2.x del código fuente de Spring, este artículo analizará cómo Spring implementa este conjunto de funciones.

Este es el tercer artículo de la serie y detallará cómo Spring sintetiza las anotaciones procesadas en anotaciones fusionadas después de la búsqueda y el mapeo de propiedades.

Artículos relacionados:

En el artículo anterior, aprendimos sobre la agregación MergedAnnotations utilizada para buscar anotaciones y AnnotationTypeMapping y AnnotationTypeMapping utilizados para completar el mapeo de atributos de anotación. Ahora necesitamos saber cómo convertir AnnotationTypeMapping y AnnotationTypeMapping en la MergedAnnotation que necesitamos en el contenedor MergedAnnotation.

Como antes, utilizamos elementos anotados. El método Findmergedannotations sirve como punto de entrada:

Encontramos el método de procesamiento de TypeMapedannotations. MergedannotationFinder Junto con MergedAnnotations.get arriba, aquí somos testigos del proceso de una metaanotación de anotación normal que se analiza en AnnotationTypeMapping y AnnotationTypeMapping:

Este método es la clave para convertir AnnotationTypeMapping en MergedAnnotation.

TypeMappedAnnotation es una implementación universal de MergedAnnotation. En la mayoría de los casos, lo que entendemos por anotaciones de fusión es en realidad esta clase.

A través de su método de construcción, podemos comprender su proceso de creación:

Se puede ver que TypeMappedAnnotation básicamente puede considerarse como una clase contenedora para AnnotationTypeMapping, que utiliza una instancia de AnnotationTypeMapping como datos. fuente, proporcionando así algunas funciones relacionadas sobre las propiedades de mapeo.

Volver al elemento anotado. FindmergedAnnotations Podemos ver que después de obtener un objeto MergedAnnotation a través de MergedAnnotation (en realidad un objeto TypeMappedAnnotation), se llama al método MergedAnnotation.synthesize para convertir MergedAnnotation en un objeto de anotación del tipo especificado por la persona que llama.

Este método primero llama al método de síntesis de AbstractMergedAnnotation:

Luego, llama al método de síntesis de la clase de implementación TypeMappedAnnotation:

Continúe haciendo clic para crear la síntesis:

El MergedAnnotationInvocationHandler sintetizado es el controlador de invocación del proxy dinámico JDK. No necesitamos mirarlo por completo. Podemos entender su mecanismo operativo con solo mirar su constructor e InvocationHandler.invoke:

En este punto, el mecanismo de síntesis de fusionar anotaciones es muy claro:

De acuerdo con lo anterior, cuando usamos el método MergedAnnotation.synthesize, podemos obtener dos tipos de objetos:

Sin embargo, cuando el valor del objeto proxy se obtiene a través de una anotación, estos métodos se delegará a la MergedAnnotation sintetizada. Llame al objeto MergedAnnotation almacenado en el controlador para que el objeto proxy pueda obtener diferentes valores de propiedad de la anotación original a través de las propiedades de la anotación original.

Cuando llamamos al valor de propiedad del objeto proxy, se enviará al método correspondiente mediante invocación en el controlador MergedAnnotationInvocation sintetizado:

Aquí, ¿cómo lo obtenemos a través del Valor del atributo de anotación del objeto proxy:

El MergedAnnotation.getValue aquí finalmente se transfiere a TypeMappedannotation. getattributevalue después de múltiples saltos:

El método getValue aquí es donde realmente se obtiene el valor del atributo.

Este paso es un poco complicado, principalmente basado en diferentes situaciones, a través de varias matrices de mapeo de atributos en AnnotationTypeMapping, incluidos aliasMappings, ConventionMappings, AnnotationValueMappings y annotationValueSource para determinar el subíndice del objeto AnnotationTypeMapping y el atributo final utilizado para consíguelo El método llamado del valor mediano:

En este punto, el proceso del método para obtener el valor del atributo también se completa.

En este capítulo, aprendimos cómo AnnotationTypeMapping se convierte en la MergedAnnotation que necesitamos después de obtener la anotación a través de MergedAnnotation y analizarla, y cómo después de esa anotación fusionada genera la anotación proxy que finalmente necesitamos.

En resumen, después de que MergedAnnotation analiza la metaanotación de la anotación para obtener el AnnotationTypeMapping requerido, determinará si AnnotationTypeMapping tiene mapeo de atributos. De lo contrario, devolverá la anotación original correspondiente al objeto de mapeo. . De lo contrario, se genera un objeto proxy dinámico JDK del tipo correspondiente a través del controlador MergedAnnotationInvocation sintetizado.

Cuando llamamos al método de anotación a través del objeto proxy para obtener el atributo de anotación, el controlador de llamadas MergedAnnotation sintetizado representará el método al método interno correspondiente, y cuando obtengamos el atributo, también lo obtendremos a través de los valores de atributo MergedAnnotation.getValue Mapping, y finalmente omitiendo AnnotationTypeMapping.