Estudio en profundidad del montaje automático Spring Boot

Anotación de modo

El modo de anotación estereotipo conocido como anotaciones, notas de primavera tiene en modo común @Service, @Repository, @Controllery así sucesivamente, que se "deriva" de @Componentcomentarios. Todos sabemos que todas las @Componentclases anotadas serán escaneadas por Spring e incluidas en el contenedor IOC, y @Componentlas clases anotadas por las anotaciones derivadas también serán escaneadas en el contenedor IOC. A continuación, llegamos a comprender principalmente @Componentla "derivación" y las "capas" a través de anotaciones de modo personalizado .

@Componente "Derivado"

Cree un nuevo proyecto de Spring Boot, la versión de Spring Boot es 2.1.0.RELEASE, artifactIdautoconfig y se introducen las spring-boot-starter-webdependencias. La estructura del proyecto es la siguiente:

En com.example.democaso de que el nuevo annotationpaquete, y luego cree un FirstLevelServicecomentario:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface FirstLevelService {
    String value() default "";
}

Esta anotación está definida por @Serviceanotaciones, @Servicey encontrará que está @Componentanotada cuando ve el código fuente , por lo que su relación jerárquica es:

└─ @ Componente
     └─ @ Servicio
          └─ @ FirstLevelService

Eso @FirstLevelServicese @Componentderiva del modo de anotación, tenemos que probar si se marcó una clase que se puede escanear en el contenedor IOC:

En com.example.demoNuevo bajo serviceel paquete, y luego cree una TestServiceclase:

@SecondLevelService
public class TestService {
}

En com.example.demoel nuevo bootstrappaquete, y luego cree una ServiceBootStrapclase para el registro de prueba TestServicey consígala del buque del COI:

@ComponentScan("com.example.demo.service")
public class ServiceBootstrap {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(ServiceBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);
        TestService testService = context.getBean("testService", TestService.class);
        System.out.println("TestService Bean: " + testService);
        context.close();
    }
}

Ejecute el método principal de esta clase, la salida de la consola es la siguiente:

@Componente "jerárquico"

Creamos com.example.demo.annotationotra SecondLevelServicedefinición de anotación debajo de la ruta , la anotación está @FirstLevelServicemarcada por lo anterior :

En este momento, la relación jerárquica es:

└─ @ Componente
     └─ @ Servicio
           └─ @ FirstLevelService
                 └─ @ SecondLevelService

Reemplazaremos la TestServiceanotación anterior con el método principal @SecondLevelServicey luego lo ejecutaremos nuevamente ServiceBootStrap, el resultado es el siguiente:

Se puede ver que el resultado también es exitoso.

Una cosa a tener en cuenta aquí es que la @Componentanotación solo contiene una definición de atributo de valor, por lo que su anotación "derivada" solo puede contener una definición de atributo de valor.

Controlador de módulo @Enable

@EnableLos controladores de módulo son compatibles después de Spring Framework 3.1. En general, el módulo aquí es una colección de componentes para lograr una determinada función. A través del @Enablecontrolador del módulo, podemos activar la función del módulo correspondiente.

@EnableLa unidad de módulo se puede dividir en dos modos de implementación: "unidad de anotación" y "programación de interfaz". La siguiente es una demostración una por una:

Basado en anotaciones

En Spring, se puede ver un ejemplo basado en anotaciones desde el @EnableWebMvccódigo fuente:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}

Esta anotación se realiza @Importimportando una clase de configuración DelegatingWebMvcConfiguration:

Esta clase de configuración se hereda de ella WebMvcConfigurationSupport, que define algunas declaraciones de Bean.

Por lo tanto, el controlador de @Enablemódulo controlado por anotaciones realmente @Importimporta una clase de configuración para realizar el registro de componentes del módulo correspondiente.Cuando estos componentes se registran en el contenedor IOC, se puede utilizar la función correspondiente de este módulo.

Definamos un @Enablecontrolador de módulo basado en anotaciones .

En com.example.demoNew Under configurationthe package, y luego cree una HelloWorldConfigurationclase de configuración:

@Configuration
public class HelloWorldConfiguration {

    @Bean
    public String hello() {
        return "hello world";
    }
}

Un helloBean con nombre se define en esta clase de configuración con contenido hello world.

Al com.example.demo.annotationcrear una siguiente EnableHelloWorlddefinición de anotación:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloWorldConfiguration.class)
public @interface EnableHelloWorld {
}

@ImportImportamos la clase de configuración que acabamos de crear en esta clase de anotación .

Luego, al com.example.demo.bootstrapcrear una próxima TestEnableBootstapclase de inicio para probar, la @EnableHelloWorldanotación está en vigor:

@EnableHelloWorld
public class TestEnableBootstap {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(TestEnableBootstap.class)
                .web(WebApplicationType.NONE)
                .run(args);
        String hello = context.getBean("hello", String.class);
        System.out.println("hello Bean: " + hello);
        context.close();
    }
}

Ejecute el método principal de esta clase, la salida de la consola es la siguiente:

Explique que nuestro sistema de anotaciones personalizado @EnableHelloWorldes factible.

Programación de interfaz

Además de utilizar el método anterior, también podemos implementar la @Enableunidad de módulo mediante la programación de la interfaz . En Spring, hay @EnableCachinganotaciones basadas en la programación de la interfaz , verifique el código fuente:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({CachingConfigurationSelector.class})
public @interface EnableCaching {
    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default 2147483647;
}

EnableCachingLas anotaciones @Importimportan una CachingConfigurationSelectorclase, que indirectamente implementa la ImportSelectorinterfaz.En el estudio en  profundidad del registro de componentes de Spring  , hemos introducido que el ImportSelectorregistro de componentes se puede lograr a través de .

Por lo tanto @Enable, la esencia de implementar la conducción de módulos a través de la programación de la interfaz es @Importimportar la ImportSelectorclase de implementación de la interfaz , que puede definir los componentes que deben registrarse en el contenedor IOC, para realizar el registro de los componentes correspondientes del módulo correspondiente.

A continuación, nos volvemos a dar cuenta de ello de acuerdo con esta idea:

En com.example.demoel nuevo selectorpaquete, luego una nueva ruta en las interfaces HelloWorldImportSelectorimplementadas ImportSelector:

public class HelloWorldImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{HelloWorldConfiguration.class.getName()};
    }
}

Si no comprende el significado del código anterior, puede leer el artículo sobre el aprendizaje en profundidad del registro de componentes de Spring .

Luego modificamos EnableHelloWorld:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(HelloWorldImportSelector.class)
public @interface EnableHelloWorld {
}

La importación anterior es HelloWorldImportSelector, no HelloWorldConfiguration.

Ejecute TestEnableBootstapel método principal nuevamente y encontrará que la salida es la misma.

Montaje automático

La capa inferior de la tecnología de ensamblaje automático en Spring Boot utiliza principalmente las siguientes tecnologías:

  1. Ensamblado de anotación en modo resorte

  2. Montaje del módulo Spring @Enable

  3. Ensamblaje condicional de Spring (introducido en el estudio en profundidad del registro de componentes de Spring )

  4. Mecanismo de carga de fábrica de resortes

La clase de implementación del mecanismo de carga de la fábrica Spring es SpringFactoriesLoader, verifique su código fuente:

El método de esta clase leerá el archivo de configuración spring.factories en el directorio META-INF. Verificamos el archivo en spring-boot-autoconfigure-2.1.0.RELEASE.jar:

Cuando se @EnableAutoConfigurationmarca la clase de inicio , todas las clases en la captura de pantalla anterior serán escaneadas por Spring para ver si se pueden incluir en el contenedor IOC para su administración.

Por ejemplo org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration, el código fuente que vimos :

Se puede ver que hay algunas anotaciones marcadas en esta categoría, entre las que se @Configurationencuentran las anotaciones de modo, la @EnableConfigurationPropertiestecnología de ensamblaje de módulos y la ConditionalOnClasstecnología de ensamblaje condicional. Esto es consistente con las principales tecnologías subyacentes del autoensamblaje de Spring Boot enumeradas anteriormente, por lo que podemos personalizar una implementación de autoensamblaje basada en esta idea.

Cree una nueva clase de configuración HelloWorldAutoConfiguration:

@Configuration
@EnableHelloWorld
@ConditionalOnProperty(name = "helloworld", havingValue = "true")
public class HelloWorldAutoConfiguration {
}

Luego cree un nuevo directorio META-INF en el directorio de recursos y cree un archivo spring.factories:

# Configurar automáticamente 
org.springframework.boot.autoconfigure.EnableAutoConfiguration = \ 
com.example.demo.configuration.HelloWorldAutoConfiguration

Luego agregue la helloworld=trueconfiguración en el archivo de configuración application.properties

hola mundo = verdadero

Finalmente cree EnableAutoConfigurationBootstrap, pruebe HelloWorldAutoConfigurationsi funciona:

@EnableAutoConfiguration
public class EnableAutoConfigurationBootstrap {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplicationBuilder(EnableAutoConfigurationBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args);
        String hello = context.getBean("hello", String.class);
        System.out.println("hello Bean: " + hello);
        context.close();
    }
}

Ejecute el método principal, la salida de la consola es la siguiente:

Demuestra que nuestro montaje automático personalizado ha tenido éxito.

A continuación se muestra un breve análisis de la lógica de ejecución del código:

  • El mecanismo de carga de fábrica de Spring leerá automáticamente el contenido del archivo spring.factories en el directorio META-INF;

  • Definimos en spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration = \ 
com.example.demo.configuration.HelloWorldAutoConfiguration

Usamos @EnableAutoConfigurationanotaciones en la clase de prueba , luego HelloWorldAutoConfigurationSpring lo escaneará para ver si cumple con los requisitos, y si cumple con los requisitos, se incluirá en el contenedor IOC;

  • HelloWorldAutoConfigurationLa función de la @ConditionalOnPropertyanotación anterior es: cuando se configura en el archivo de configuración helloworld=true(agregamos esta configuración, por lo que cumple con los requisitos), esta clase cumple con las reglas de escaneo; la @EnableHelloWorldanotación es una anotación personalizada impulsada por un módulo en nuestro ejemplo anterior, que introduce el hello Bean, por lo que el hello bean existirá en el contenedor IOC;

  • A través de los pasos anteriores, podemos obtener el bean hello a través del contexto.

 

Supongo que te gusta

Origin blog.csdn.net/u014225733/article/details/100836544
Recomendado
Clasificación