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.