Analyse des composants de printemps

Balayage des composants Spring

1. Vue d'ensemble

Dans ce didacticiel, nous aborderons l'analyse des composants dans Spring. Lorsque vous travaillez avec Spring, nous pouvons annoter nos classes afin de les transformer en haricots Spring. Mais, à part cela,we can tell Spring where to search for these annotated classes car tous ne doivent pas devenir des beans dans cette exécution particulière.

Bien sûr, il existe certaines valeurs par défaut pour l'analyse des composants, mais nous pouvons également personnaliser les packages pour la recherche.

Tout d'abord, examinons les paramètres par défaut.

2. @ComponentScan sans arguments

2.1. Utilisation de@ComponentScan dans une application Spring

Avec Spring,we use the @ComponentScan annotation along with @Configuration annotation to specify the packages that we want to be scanned. @ComponentScan sans arguments indique à Spring d'analyser le package actuel et tous ses sous-packages.

Supposons que nous ayons les@Configuration suivants dans le packagecom.example.componentscan.springapp:

@Configuration
@ComponentScan
public class SpringComponentScanApp {
    private static ApplicationContext applicationContext;

    @Bean
    public ExampleBean exampleBean() {
        return new ExampleBean();
    }

    public static void main(String[] args) {
        applicationContext =
          new AnnotationConfigApplicationContext(SpringComponentScanApp.class);

        for (String beanName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanName);
        }
    }
}

Supposons également que nous ayons les composantsCat etDog dans le packagecom.example.componentscan.springapp.animals:

package com.example.componentscan.springapp.animals;
// ...
@Component
public class Cat {}
package com.example.componentscan.springapp.animals;
// ...
@Component
public class Dog {}

Et enfin, nous avons le composantRose dans le packagecom.example.componentscan.springapp.flowers:

package com.example.componentscan.springapp.flowers;
// ...
@Component
public class Rose {}

La sortie de la méthodemain() contiendra tous les beans du packagecom.example.componentscan.springapp et de ses sous-packages:

springComponentScanApp
cat
dog
rose
exampleBean

Notez que la classe d'application principale est également un bean car elle est annotée avec@Configuration, qui est un@Component.

Notez également que la classe d'application principale et la classe de configuration ne sont pas nécessairement identiques. S'ils sont différents, peu importe où placer la classe d'application principale. Only the location of the configuration class matters as component scanning starts from its package by default.

Enfin, notez que dans notre exemple@ComponentScan équivaut à:

@ComponentScan(basePackages = "com.example.componentscan.springapp")

où l'argumentbasePackages est un package ou un tableau de packages à analyser.

2.2. Utilisation de@ComponentScan dans une application Spring Boot

Le truc avec Spring Boot est que beaucoup de choses se passent implicitement. Nous utilisons l'annotation@SpringBootApplication, mais il s'agit simplement d'une combinaison de trois annotations:

@Configuration
@EnableAutoConfiguration
@ComponentScan

Créons une structure similaire dans le packagecom.example.componentscan.springbootapp. Cette fois l'application principale sera:

package com.example.componentscan.springbootapp;
// ...
@SpringBootApplication
public class SpringBootComponentScanApp {
    private static ApplicationContext applicationContext;

    @Bean
    public ExampleBean exampleBean() {
        return new ExampleBean();
    }

    public static void main(String[] args) {
        applicationContext = SpringApplication.run(SpringBootComponentScanApp.class, args);
        checkBeansPresence(
          "cat", "dog", "rose", "exampleBean", "springBootComponentScanApp");

    }

    private static void checkBeansPresence(String... beans) {
        for (String beanName : beans) {
            System.out.println("Is " + beanName + " in ApplicationContext: " +
              applicationContext.containsBean(beanName));
        }
    }
}

Tous les autres packages et classes restent les mêmes, nous allons simplement les copier dans le packagecom.example.componentscan.springbootapp à proximité.

Spring Boot analyse les paquets de la même manière que dans notre exemple précédent. Vérifions le résultat:

Is cat in ApplicationContext: true
Is dog in ApplicationContext: true
Is rose in ApplicationContext: true
Is exampleBean in ApplicationContext: true
Is springBootComponentScanApp in ApplicationContext: true

La raison pour laquelle nous vérifions simplement l’existence des beans dans notre deuxième exemple (par opposition à l’impression de tous les beans), est que la sortie serait trop volumineuse.

Ceci est dû à l'annotation implicite@EnableAutoConfiguration qui fait que Spring Boot crée automatiquement de nombreux beans, en se basant sur les dépendances dans le fichierpom.xml.

3. @ComponentScan avec des arguments

Personnalisons maintenant les chemins de numérisation. Par exemple, disons que nous voulons exclure le beanRose.

3.1. @ComponentScan pour des packages spécifiques

Nous pouvons le faire de plusieurs manières. Premièrement, nous pouvons changer le paquet de base:

@ComponentScan(basePackages = "com.example.componentscan.springapp.animals")
@Configuration
public class SpringComponentScanApp {
   // ...
}

Maintenant, le résultat sera:

springComponentScanApp
cat
dog
exampleBean

Voyons ce qu'il y a derrière cela:

  • springComponentScanApp est créé car il s'agit d'une configuration passée en argument auxAnnotationConfigApplicationContext

  • exampleBean est un bean configuré dans la configuration

  • cat etdog sont dans le packagecom.example.componentscan.springapp.animals spécifié

Toutes les personnalisations répertoriées ci-dessus sont également applicables dans Spring Boot. Nous pouvons utiliser@ComponentScan avec@SpringBootApplication et le résultat sera le même:

@SpringBootApplication
@ComponentScan(basePackages = "com.example.componentscan.springbootapp.animals")

3.2. @ComponentScan avec exclusions

Une autre méthode consiste à utiliser un filtre, en spécifiant le modèle d'exclusion des classes:

@ComponentScan(excludeFilters =
  @ComponentScan.Filter(type=FilterType.REGEX,
    pattern="com\\.example\\.componentscan\\.springapp\\.flowers\\..*"))

Nous pouvons également choisir un type de filtre différent, commethe annotation supports several flexible options for filtering the scanned classes:

@ComponentScan(excludeFilters =
  @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = Rose.class))

4. Le package par défaut

Il faut éviter de mettre la classe@Configurationin the default package (i.e. en ne spécifiant pas du tout le paquet). Dans ce cas, Spring analyse toutes les classes de tous les fichiers jars d'un chemin de classe. Cela provoque des erreurs et l'application ne démarre probablement pas.

5. Conclusion

Dans cet article, nous avons appris quels packages Spring scanne par défaut et comment personnaliser ces chemins.

Comme d'habitude, le code complet est disponibleover on GitHub.