Etude approfondie de l'assemblage automatique Spring Boot

Annotation de mode

Stéréotype mode Annotation connu sous forme d' annotations, les notes de printemps ont en mode commun @Service, @Repository, @Controlleret ainsi de suite, ils sont « dérivés » de @Componentcommentaires. Nous savons tous que toutes les @Componentclasses annotées seront scannées par Spring et incluses dans le conteneur IOC, et @Componentles classes annotées par les annotations dérivées seront également scannées dans le conteneur IOC. Ci-dessous, nous arrivons principalement à comprendre @Componentla «dérivation» et la «superposition» à travers les annotations en mode personnalisé .

@Component "Dérivée"

Créez un nouveau projet Spring Boot, la version Spring Boot est 2.1.0.RELEASE, la artifactIdconfiguration automatique et les spring-boot-starter-webdépendances sont introduites . La structure du projet est la suivante:

Dans le com.example.democas du nouveau annotationpackage, puis créez un FirstLevelServicecommentaire:

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

Cette annotation est définie par des @Serviceannotations, @Serviceet vous constaterez qu'elle est @Componentannotée lorsque vous affichez le code source , de sorte que leur relation hiérarchique est:

└─ @ Composant
     └─ @ Service
          └─ @ FirstLevelService

Cela @FirstLevelServiceest @Componentdérivé du mode d'annotation, nous devons tester si elle a marqué une classe peut être scannée dans le conteneur IOC:

Dans com.example.demoNouveau sous servicele package, puis créez une TestServiceclasse:

@SecondLevelService
public class TestService {
}

Dans com.example.demole nouveau bootstrappackage, puis créez une ServiceBootStrapclasse pour le registre de test TestServiceet obtenez-la du navire du CIO:

@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();
    }
}

Exécutez la méthode principale de cette classe, la sortie de la console est la suivante:

@Component "hiérarchique"

Nous com.example.demo.annotationcréons une autre SecondLevelServicedéfinition d'annotation sous le chemin , l'annotation est @FirstLevelServicemarquée par ce qui précède :

À ce stade, la relation hiérarchique est:

└─ @ Component
     └─ @ Service
           └─ @ FirstLevelService
                 └─ @ SecondLevelService

Nous remplacerons l' TestServiceannotation ci - dessus par la méthode principale, @SecondLevelServicepuis la réexécuterons ServiceBootStrap, le résultat est le suivant:

On voit que le résultat est également réussi.

Une chose à noter ici est que l' @Componentannotation ne contient qu'une seule définition d'attribut de valeur, de sorte que son annotation «dérivée» ne peut contenir qu'une seule définition d'attribut de valeur.

@Activer le pilote du module

@EnableLes pilotes de module sont pris en charge après Spring Framework 3.1. En général, le module est ici un ensemble de composants pour réaliser une certaine fonction. Grâce au @Enablepilote de module, nous pouvons activer la fonction de module correspondante.

@EnableL'entraînement du module peut être divisé en deux modes d'implémentation: «entraînement d'annotation» et «programmation d'interface». Voici une démonstration un par un:

Piloté par les annotations

Dans Spring, un exemple basé sur les annotations peut être visualisé à partir du @EnableWebMvccode source:

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

Cette annotation se fait en @Importimportant une classe de configuration DelegatingWebMvcConfiguration:

Cette classe de configuration en est héritée WebMvcConfigurationSupport, ce qui définit certaines déclarations Bean.

Par conséquent, le @Enablepilote de module piloté par annotations @Importimporte en fait une classe de configuration pour réaliser l'enregistrement des composants du module correspondant.Lorsque ces composants sont enregistrés dans le conteneur IOC, la fonction correspondante de ce module peut être utilisée.

Définissons un @Enablepilote de module basé sur des annotations .

Dans com.example.demoNouveau sous configurationle package, puis créez une HelloWorldConfigurationclasse de configuration:

@Configuration
public class HelloWorldConfiguration {

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

Un helloBean nommé est défini dans cette classe de configuration avec le contenu hello world.

Lors de la com.example.demo.annotationcréation d'une prochaine EnableHelloWorlddéfinition d'annotation:

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

Nous avons @Importimporté la classe de configuration que nous venons de créer sur cette classe d' annotation .

Ensuite, lors de la com.example.demo.bootstrapcréation d'une prochaine TestEnableBootstapclasse de démarrage pour tester l' @EnableHelloWorldannotation est en vigueur:

@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();
    }
}

Exécutez la méthode principale de cette classe, la sortie de la console est la suivante:

Expliquez que notre fonction d'annotation personnalisée @EnableHelloWorldest faisable.

Programmation d'interface

En plus d'utiliser la méthode ci-dessus, nous pouvons également implémenter le @Enablelecteur de module via la programmation d'interface . Au printemps, il existe des @EnableCachingannotations basées sur la programmation d'interface , vérifiez le code source:

@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;
}

EnableCachingLes annotations @Importimportent une CachingConfigurationSelectorclasse, qui implémente indirectement l' ImportSelectorinterface.Dans l'  étude approfondie de l'enregistrement des composants Spring  , nous avons introduit que l' ImportSelectorenregistrement des composants peut être réalisé via .

Par conséquent @Enable, l'essence de la mise en œuvre du pilotage de module via la programmation d'interface est @Importd'importer la ImportSelectorclasse d'implémentation d' interface , qui peut définir les composants qui doivent être enregistrés dans le conteneur IOC, afin de réaliser l'enregistrement des composants correspondants du module correspondant.

Ensuite, on en vient à le réaliser à nouveau selon cette idée:

Dans com.example.demole nouveau selectorpaquet, puis un nouveau chemin dans les interfaces HelloWorldImportSelectorimplémentées ImportSelector:

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

Si vous ne comprenez pas la signification du code ci-dessus, vous pouvez lire l' article sur l' apprentissage approfondi de l'enregistrement des composants Spring .

Puis on modifie EnableHelloWorld:

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

L'importation ci-dessus ne l'est HelloWorldImportSelectorpas HelloWorldConfiguration.

Exécutez à nouveau la TestEnableBootstapméthode principale et vous constaterez que la sortie est la même.

Assemblage automatique

La couche inférieure de la technologie d'assemblage automatique de Spring Boot utilise principalement les technologies suivantes:

  1. Assemblage d'annotation en mode ressort

  2. Assemblage du module Spring @Enable

  3. Assemblage conditionnel Spring (introduit dans l'étude approfondie de l'enregistrement des composants Spring )

  4. Mécanisme de chargement d'usine à ressort

La classe d'implémentation du mécanisme de chargement d'usine Spring est SpringFactoriesLoader, vérifiez son code source:

La méthode de cette classe lira le fichier de configuration spring.factories sous le répertoire META-INF. Nous vérifions le fichier sous spring-boot-autoconfigure-2.1.0.RELEASE.jar:

Lorsque la classe de démarrage est @EnableAutoConfigurationmarquée, toutes les classes de la capture d'écran ci-dessus seront analysées par Spring pour voir si elles peuvent être incluses dans le conteneur IOC pour la gestion.

Par exemple org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration, le code source que nous avons consulté :

On peut voir que certaines annotations sont marquées dans cette catégorie, parmi lesquelles @Configurationles annotations de mode, la @EnableConfigurationPropertiestechnologie d'assemblage de module et la ConditionalOnClasstechnologie d'assemblage conditionnel. Ceci est cohérent avec les principales technologies sous-jacentes de l'assemblage automatique Spring Boot répertoriées ci-dessus, nous pouvons donc personnaliser une implémentation d'assemblage automatique en fonction de cette idée.

Créez une nouvelle classe de configuration HelloWorldAutoConfiguration:

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

Ensuite, créez un nouveau répertoire META-INF sous le répertoire resources et créez un fichier spring.factories:

# Configurer automatiquement 
org.springframework.boot.autoconfigure.EnableAutoConfiguration = \ 
com.example.demo.configuration.HelloWorldAutoConfiguration

Ajoutez ensuite la helloworld=trueconfiguration dans le fichier de configuration application.properties

helloworld = vrai

Enfin créez EnableAutoConfigurationBootstrap, testez HelloWorldAutoConfigurationsi cela fonctionne:

@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();
    }
}

Exécutez la méthode principale, la sortie de la console est la suivante:

Cela montre que notre assemblage automatique personnalisé a réussi.

Voici une brève analyse de la logique d'exécution du code:

  • Le mécanisme de chargement d'usine de Spring lira automatiquement le contenu du fichier spring.factories dans le répertoire META-INF;

  • Nous avons défini dans spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration = \ 
com.example.demo.configuration.HelloWorldAutoConfiguration

Nous utilisons des @EnableAutoConfigurationannotations sur la classe de test , puis HelloWorldAutoConfigurationelle sera analysée par Spring pour voir si elle répond aux exigences, et si elle répond aux exigences, elle sera incluse dans le conteneur IOC;

  • HelloWorldAutoConfigurationLa fonction de l' @ConditionalOnPropertyannotation ci - dessus est: lorsqu'elle est configurée dans le fichier de configuration helloworld=true(nous avons ajouté cette configuration, elle répond donc aux exigences), cette classe répond aux règles d'analyse; l' @EnableHelloWorldannotation est une annotation personnalisée pilotée par module dans notre exemple précédent, introduit le bean hello, donc le bean hello existera dans le conteneur IOC;

  • Grâce aux étapes ci-dessus, nous pouvons obtenir le bean bonjour à travers le contexte.

 

Je suppose que tu aimes

Origine blog.csdn.net/u014225733/article/details/100836544
conseillé
Classement