web-dev-qa-db-fra.com

Différence entre <contexte: annotation-config> vs <contexte: composant-scan>

J'apprends le printemps 3 et je ne semble pas comprendre la fonctionnalité derrière <context:annotation-config> et <context:component-scan>.

D'après ce que j'ai lu, ils semblent gérer différentes annotations (@Required, @Autowired, etc., vs @Component, @Repository, @Service, etc.), mais ils ont également enregistré les mêmes classes de post-traitement de beans.

Pour me troubler encore plus, il existe un attribut annotation-config sur <context:component-scan>.

Quelqu'un peut-il faire la lumière sur ces balises? Qu'est-ce qui est semblable, ce qui est différent, l'un est-il remplacé par l'autre, ils se complètent, est-ce que j'ai besoin de l'un d'eux, des deux?

634
user938214097

<context:annotation-config> est utilisé pour activer les annotations dans les beans déjà enregistrés dans le contexte d'application (qu'ils aient été définis avec XML ou par analyse de package).

<context:component-scan> peut également faire ce que <context:annotation-config> fait, mais <context:component-scan> analyse également les packages pour rechercher et enregistrer des beans dans le contexte de l'application.

Je vais utiliser quelques exemples pour montrer les différences/similitudes. 

Commençons par une configuration de base de trois beans de type A, B et C, avec B et C injectés dans A.

package com.xxx;
public class B {
  public B() {
    System.out.println("creating bean B: " + this);
  }
}

package com.xxx;
public class C {
  public C() {
    System.out.println("creating bean C: " + this);
  }
}

package com.yyy;
import com.xxx.B;
import com.xxx.C;
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc; 
  }
}

Avec la configuration XML suivante:

<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A">
  <property name="bbb" ref="bBean" />
  <property name="ccc" ref="cBean" />
</bean>

Le chargement du contexte produit la sortie suivante:

creating bean B: com.xxx.B@c2ff5
creating bean C: com.xxx.C@1e8a1f6
creating bean A: com.yyy.A@1e152c5
setting A.bbb with com.xxx.B@c2ff5
setting A.ccc with com.xxx.C@1e8a1f6

OK, c'est la sortie attendue. Mais c'est le printemps "à l'ancienne". Nous avons maintenant des annotations, alors utilisons-les pour simplifier le XML.

Premièrement, laisse autowire les propriétés bbb et ccc sur le bean A comme ceci:

package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import com.xxx.B;
import com.xxx.C;
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  @Autowired
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  @Autowired
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc;
  }
}

Cela me permet de supprimer les lignes suivantes du XML:

<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />

Mon XML est maintenant simplifié à ceci:

<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

Lorsque je charge le contexte, j'obtiens la sortie suivante:

creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf

OK, c'est faux! Qu'est-il arrivé? Pourquoi mes propriétés ne sont-elles pas câblées automatiquement?

Les annotations sont une fonctionnalité de Nice, mais elles ne font rien d’elles-mêmes. Ils annotent juste des trucs. Vous avez besoin d'un outil de traitement pour trouver les annotations et faire quelque chose avec elles. 

<context:annotation-config> à la rescousse. Cela active les actions pour les annotations trouvées sur les beans définis dans le même contexte d'application que celui où il est lui-même défini.

Si je change mon XML en ceci:

<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

lorsque je charge le contexte de l'application, le résultat est correct:

creating bean B: com.xxx.B@15663a2
creating bean C: com.xxx.C@cd5f8b
creating bean A: com.yyy.A@157aa53
setting A.bbb with com.xxx.B@15663a2
setting A.ccc with com.xxx.C@cd5f8b

OK, c’est bien, mais j’ai supprimé deux lignes du fichier XML et en ai ajouté une. Ce n'est pas une très grande différence. L'idée avec les annotations est qu'elle est supposée supprimer le XML.

Supprimons donc les définitions XML et les remplaçons toutes par des annotations:

package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class B {
  public B() {
    System.out.println("creating bean B: " + this);
  }
}

package com.xxx;
import org.springframework.stereotype.Component;
@Component
public class C {
  public C() {
    System.out.println("creating bean C: " + this);
  }
}

package com.yyy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.xxx.B;
import com.xxx.C;
@Component
public class A { 
  private B bbb;
  private C ccc;
  public A() {
    System.out.println("creating bean A: " + this);
  }
  @Autowired
  public void setBbb(B bbb) {
    System.out.println("setting A.bbb with " + bbb);
    this.bbb = bbb;
  }
  @Autowired
  public void setCcc(C ccc) {
    System.out.println("setting A.ccc with " + ccc);
    this.ccc = ccc;
  }
}

Dans le XML, nous ne gardons que ceci:

<context:annotation-config />

Nous chargeons le contexte et le résultat est ... Rien. Aucun haricot n'est créé, aucun haricot n'est câblé automatiquement. Rien!

En effet, comme je l’ai dit dans le premier paragraphe, le <context:annotation-config /> ne fonctionne que sur les beans enregistrés dans le contexte de l’application. Comme j'ai supprimé la configuration XML pour les trois beans, aucun bean n'a été créé et <context:annotation-config /> n'a pas de "cible" sur laquelle travailler.

Mais ce ne sera pas un problème pour <context:component-scan> qui peut analyser un paquet sur lequel travailler "les cibles". Modifions le contenu de la configuration XML dans l'entrée suivante:

<context:component-scan base-package="com.xxx" />

Lorsque je charge le contexte, j'obtiens la sortie suivante:

creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff

Hmmmm ... il manque quelque chose. Pourquoi? 

Si vous regardez attentivement les classes, la classe A a le paquet com.yyy mais j'ai spécifié dans le <context:component-scan> d'utiliser le paquet com.xxx, donc cela a complètement manqué ma classe A et n'a ramassé que B et C qui sont sur le paquet com.xxx.

Pour résoudre ce problème, j'ajoute également cet autre package:

<context:component-scan base-package="com.xxx,com.yyy" />

et maintenant nous obtenons le résultat attendu:

creating bean B: com.xxx.B@cd5f8b
creating bean C: com.xxx.C@15ac3c9
creating bean A: com.yyy.A@ec4a87
setting A.bbb with com.xxx.B@cd5f8b
setting A.ccc with com.xxx.C@15ac3c9

Et c'est tout! Maintenant, vous n'avez plus de définitions XML, vous avez des annotations.

Comme dernier exemple, en conservant les classes annotées A, B et C et en ajoutant ce qui suit au XML, que va-t-on obtenir après le chargement du contexte?

<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

Nous obtenons toujours le résultat correct:

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

Même si le bean de la classe A n'est pas obtenu par analyse, les outils de traitement sont toujours appliqués par <context:component-scan> sur tous les beans enregistrés dans le contexte de l'application, même pour A qui a été manuellement enregistré dans le fichier XML.

Mais que se passe-t-il si nous avons le code XML suivant, obtiendrons-nous des beans dupliqués car nous avons spécifié à la fois <context:annotation-config /> et <context:component-scan>?

<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

Non, pas de doublons, nous obtenons encore le résultat attendu:

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@1d64c37
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

En effet, les deux balises enregistrent les mêmes outils de traitement (<context:annotation-config /> peut être omis si <context:component-scan> est spécifié) mais Spring ne les exécute qu'une seule fois.

Même si vous enregistrez vous-même plusieurs fois les outils de traitement, Spring veillera à ce qu'ils ne fassent leur magie qu'une seule fois; ce XML:

<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
<bean id="bla" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla1" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla2" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean id="bla3" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />

générera toujours le résultat suivant:

creating bean B: com.xxx.B@157aa53
creating bean C: com.xxx.C@ec4a87
creating bean A: com.yyy.A@25d2b2
setting A.bbb with com.xxx.B@157aa53
setting A.ccc with com.xxx.C@ec4a87

OK, c'est à propos de ça. 

J'espère que cette information ainsi que les réponses de @Tomasz Nurkiewicz et de @Sean Patrick Floyd sont tout ce dont vous avez besoin pour comprendre le fonctionnement de <context:annotation-config> et <context:component-scan>.

1341
user159088

J'ai trouvé ce Nice résumé dont les annotations sont prises en compte par quelles déclarations. En l'étudiant, vous constaterez que <context:component-scan/> reconnaît un sur-ensemble d'annotations reconnu par <context:annotation-config/>, à savoir:

  • @Component, @Service, @Repository, @Controller, @Endpoint
  • @Configuration, @Bean, @Lazy, @Scope, @Order, @Primary, @Profile, @DependsOn, @Import, @ImportResource__

Comme vous pouvez le voir logiquement <context:component-scan/>extend<context:annotation-config/> avec les fonctions d'analyse du composant CLASSPATH et de Java @Configuration.

160
Tomasz Nurkiewicz

Le printemps vous permet de faire deux choses:

  1. Autowiring de haricots
  2. Autodiscovery de haricots

1. Autowiring
Généralement, dans applicationContext.xml, vous définissez des beans et d'autres beans sont câblés à l'aide de méthodes de constructeur ou de définition Vous pouvez câbler des beans en utilisant XML ou des annotations . Si vous utilisez des annotations, vous devez activer des annotations et vous devez ajouter <context:annotation-config /> dans applicationContext.xml. Cela simplifiera la structure De la balise de applicationContext.xml, car vous ne devrez pas câbler manuellement les beans (constructeur ou setter). Vous pouvez utiliser l'annotation @Autowire et les beans seront câblés par type.

Un pas en avant pour échapper à la configuration XML manuelle est 

2. Autodiscovery
L'autodiscovery simplifie encore le XML, dans la mesure où vous n'avez même pas besoin d'ajouter la balise <bean> dans applicationContext.xml. Vous venez de marquer les haricots spécifiques avec l'une des annotations suivantes et Spring connectera automatiquement les haricots marqués et leurs dépendances au conteneur Spring. Les annotations sont les suivantes: @Controller, @Service, @Component, @Repository. En utilisant <context:component-scan> et en pointant le package de base, Spring détecte et connecte automatiquement les composants dans un conteneur Spring.


Comme conclusion:

  • <context:annotation-config /> est utilisé pour pouvoir utiliser l'annotation @Autowired
  • <context:component-scan /> est utilisé pour déterminer la recherche de beans spécifiques et la tentative de câblage automatique.
85
user2673474

<context:annotation-config> active de nombreuses annotations différentes dans les beans, qu'elles soient définies en XML ou lors de l'analyse de composants.

<context:component-scan> sert à définir des beans sans utiliser XML

Pour plus d'informations, lisez:

31
Sean Patrick Floyd

La différence entre les deux est très simple!.

<context:annotation-config /> 

Vous permet d'utiliser des annotations restreintes au câblage des propriétés et des constructeurs de beans uniquement!.

Tandis que

<context:component-scan base-package="org.package"/> 

Active tout ce que <context:annotation-config /> peut faire, avec l’ajout de stéréotypes, par exemple .. @Component, @Service, @Repository. Ainsi, vous pouvez câbler des haricots entiers et pas seulement restreints aux constructeurs ou aux propriétés !. 

28
Sparticles

<context:annotation-config>: Analyse et activation d'annotations pour les beans déjà enregistrés dans spring config xml.

<context:component-scan>: Enregistrement du bean + <context:annotation-config>


@Autowired et @Required sont niveau de propriété des cibles}, donc bean doit être enregistré au printemps IOC avant d'utiliser ces annotations. Pour activer ces annotations, vous devez soit enregistrer les beans respectifs, soit inclure <context:annotation-config /><context:annotation-config /> fonctionne uniquement avec les beans enregistrés.

@Required active l'outil de traitement RequiredAnnotationBeanPostProcessor
@Autowired active l'outil de traitement AutowiredAnnotationBeanPostProcessor

Note: L'annotation elle-même n'a rien à faire, nous avons besoin d'un outil de traitement, qui est une classe située en dessous, responsable du processus principal.


@Repository, @Service et @Controller sont @Component, et ils niveau de classe des cibles.

<context:component-scan> il analyse le package, trouve et enregistre les beans et inclut le travail effectué par <context:annotation-config />.

Migration de XML en annotations

24
Premraj

La balise <context:annotation-config> indique à Spring d'analyser la base de code pour résoudre automatiquement les conditions de dépendance des classes contenant l'annotation @Autowired.

Spring 2.5 prend également en charge les annotations JSR-250 telles que @Resource, @PostConstruct et @ PreDestroy.L'utilisation de ces annotations nécessite également que certains BeanPostProcessors soient enregistrés dans le conteneur Spring. Comme toujours, elles peuvent être enregistrées en tant que définitions de beans individuelles, mais elles peuvent également être implicitement enregistrées en incluant la balise <context:annotation-config> dans la configuration de printemps.

Extrait de la documentation Spring de Configuration basée sur les annotations


Spring offre la possibilité de détecter automatiquement les classes «stéréotypées» et d'enregistrer les définitions BeanDefinitions correspondantes dans ApplicationContext.

Selon javadoc de org.springframework.stereotype :

Les stéréotypes sont des annotations indiquant les rôles des types ou des méthodes dans l'architecture globale (au niveau conceptuel plutôt qu'au niveau de la mise en œuvre). Exemple: @Controller @Service @Repository etc . Celles-ci sont destinées à être utilisées par des outils et des aspects (ce qui en fait une cible idéale pour les découpages ponctuels).

Pour détecter automatiquement ces classes "stéréotypées", la balise <context:component-scan> est requise.

La balise <context:component-scan> indique également à Spring d'analyser le code des haricots injectables sous le package (et tous ses sous-packages) spécifié.

15
Sachin Sharma
<context:annotation-config>

Seulement résout les annotations @Autowired et @Qualifer, c'est tout/ça concerne la Dépendance Injection , Il y a d'autres annotations qui font le même travail, je pense comment @Inject, mais sur le point de résoudre DI par annotations.

Sachez que, même lorsque vous avez déclaré l'élément <context:annotation-config>, vous devez déclarer votre classe comme un bean de toute façon, rappelez-vous que nous avons trois options disponibles.

  • XML: <bean> 
  • @Annotations: @Component, @Service, @Repository, @Controller 
  • JavaConfig: @Configuration, @Bean

Maintenant avec

<context:component-scan>

Il fait deux choses:

  • Il analyse toutes les classes annotées avec @ Component, @Service, @Repository, @Controller et @Configuration et crée un bean
  • Il fait le même travail que <context:annotation-config>.

Par conséquent, si vous déclarez <context:component-scan>, ce n'est plus nécessaire, déclarez également <context:annotation-config>.

C'est tout 

Un scénario courant consistait par exemple à déclarer uniquement un bean via XML et à résoudre l'ID par le biais d'annotations, par exemple

<bean id="serviceBeanA" class="com.something.CarServiceImpl" />
<bean id="serviceBeanB" class="com.something.PersonServiceImpl" />
<bean id="repositoryBeanA" class="com.something.CarRepository" />
<bean id="repositoryBeanB" class="com.something.PersonRepository" />

Nous avons seulement déclaré les beans, rien sur <constructor-arg> et <property>, la DI est configurée dans ses propres classes via @Autowired. Cela signifie que les services utilisent @Autowired pour leurs composants de référentiels et que les référentiels utilisent @Autowired pour JdbcTemplate, DataSource etc..components.

10
Manuel Jordan
<context:component-scan /> implicitly enables <context:annotation-config/>

essayez avec <context:component-scan base-package="..." annotation-config="false"/> dans votre configuration @Service, @Repository, @Component fonctionne bien, mais @ Autowired, @ Resource et @Inject ne fonctionne pas.

Cela signifie que AutowiredAnnotationBeanPostProcessor ne sera pas activé et que le conteneur Spring ne traitera pas les annotations de transfert automatique.

6
Lovababu
<context:annotation-config/> <!-- is used to activate the annotation for beans -->
<context:component-scan base-package="x.y.MyClass" /> <!-- is for the Spring IOC container to look for the beans in the base package. -->

L'autre point important à noter est que context:component-scan appelle implicitement le context:annotation-config pour activer les annotations sur les beans. Si vous ne voulez pas que context:component-scan active implicitement les annotations pour vous, vous pouvez définir l'élément annotation-config de context:component-scan sur false.

Résumer:

<context:annotation-config/> <!-- activates the annotations --> 
<context:component-scan base-package="x.y.MyClass" /> <!-- activates the annotations + register the beans by looking inside the base-package -->
5
Abdullah Khan

Une balise personnalisée <context:component-scan/> enregistre le même ensemble de définitions de bean que celui utilisé par, à part sa responsabilité principale qui consiste à analyser les packages Java et à enregistrer les définitions de bean à partir du chemin de classe.

Si, pour quelque raison que ce soit, cet enregistrement des définitions de bean par défaut doit être évité, vous devez pour cela spécifier un attribut supplémentaire "annotation-config" dans composant-scan:

<context:component-scan basePackages="" annotation-config="false"/>

Référence: http://www.Java-allandsundry.com/2012/12/12/contextcomponent-scan-contextannotation.html

0
Abhishek Gaur

<context:component-scan base-package="package name" />:

Ceci est utilisé pour indiquer au conteneur qu'il existe des classes de beans dans mon paquet, analyser ces classes de beans. Pour analyser les classes de beans par conteneur au-dessus du bean, nous devons écrire une annotation de type stéréo comme suit.

@Component, @Service, @Repository, @Controller

<context:annotation-config />:

Si nous ne voulons pas écrire la balise de bean explicitement en XML, comment le conteneur sait s'il y a un câblage automatique dans le bean. Ceci est possible en utilisant l'annotation @Autowired. nous devons informer le conteneur qu'il y a un câblage automatique dans mon bean par context:annotation-config.

0
Pulipati Prasadarao

En complément, vous pouvez utiliser @ComponentScan pour utiliser <context:component-scan> de manière annotée.

Il est également décrit à spring.io

Configure les directives d'analyse des composants à utiliser avec les classes @Configuration. Fournit une prise en charge parallèle à l'élément Spring XML.

Une chose à noter, si vous utilisez Spring Boot, les @Configuration et @ComponentScan peuvent être impliquées en utilisant l'annotation @SpringBootApplication.

0
Gearon

<context:annotation-config>:

Cela indique à Spring que je vais utiliser les haricots annotés comme haricots de printemps et que ceux-ci seraient câblés avec l'annotation @Autowired au lieu d'être déclarés dans un fichier XML de configuration print.

<context:component-scan base-package="com.test...">

Cela indique au conteneur Spring où commencer la recherche des haricots annotés. Ici, spring recherchera tous les sous-packages du package de base.

0
Sajal Chakraborty

vous pouvez trouver plus d'informations dans le fichier de schéma de contexte de printemps .

<conxtext:annotation-config />
Activates various annotations to be detected in bean classes: Spring's @Required and
@Autowired, as well as JSR 250's @PostConstruct, @PreDestroy and @Resource (if available),
JAX-WS's @WebServiceRef (if available), EJB 3's @EJB (if available), and JPA's
@PersistenceContext and @PersistenceUnit (if available). Alternatively, you may
choose to activate the individual BeanPostProcessors for those annotations.

Note: This tag does not activate processing of Spring's @Transactional or EJB 3's
@TransactionAttribute annotation. Consider the use of the <tx:annotation-driven>
tag for that purpose.
<context:component-scan>
Scans the classpath for annotated components that will be auto-registered as
Spring beans. By default, the Spring-provided @Component, @Repository, @Service, @Controller, @RestController, @ControllerAdvice, and @Configuration stereotypes    will be detected.

Note: This tag implies the effects of the 'annotation-config' tag, activating @Required,
@Autowired, @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and @PersistenceUnit
annotations in the component classes, which is usually desired for autodetected components
(without external configuration). Turn off the 'annotation-config' attribute to deactivate
this default behavior, for example in order to use custom BeanPostProcessor definitions
for handling those annotations.

Note: You may use placeholders in package paths, but only resolved against system
properties (analogous to resource paths). A component scan results in new bean definitions
being registered; Spring's PropertySourcesPlaceholderConfigurer will apply to those bean
definitions just like to regular bean definitions, but it won't apply to the component
scan settings themselves.
0
coffeenjava