<context:annotation-config>
est utilisé pour activer les annotations dans les beans déjà enregistrés dans le contexte de l'application (peu importe s'ils ont été définis avec XML ou par analyse de package).
<context:component-scan>
peut également faire ce qu'il <context:annotation-config>
fait mais <context:component-scan>
analyse également les packages pour trouver 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 grains de type A
, B
et C
, avec B
et C
injecté 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". Maintenant que nous avons des annotations, utilisons-les pour simplifier le XML.
Tout d'abord, permet de câbler automatiquement 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?
Eh bien, les annotations sont une fonctionnalité intéressante, mais en elles-mêmes, elles ne font absolument rien. 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 qu'il trouve sur les beans définis dans le même contexte d'application où lui-même est 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, j'obtiens le bon résultat:
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 XML et j'en ai ajouté une. Ce n'est pas une très grande différence. L'idée avec des annotations est qu'il est censé supprimer le XML.
Supprimons donc les définitions XML et remplaçons-les 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 bean n'est créé, aucun bean n'est câblé automatiquement. Rien!
En effet, comme je l'ai dit dans le premier paragraphe, les <context:annotation-config />
seuls travaux sur les beans enregistrés dans le contexte de l'application. Parce que j'ai supprimé la configuration XML pour les trois beans, aucun bean n'a été créé et <context:annotation-config />
n'a pas de "cibles" sur lesquelles travailler.
Mais ce ne sera pas un problème pour <context:component-scan>
lequel peut analyser un package pour les "cibles" sur lesquelles travailler. 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 de près les classes, la classe A
a un package, com.yyy
mais j'ai spécifié dans le <context:component-scan>
package à utiliser, com.xxx
donc cela a complètement manqué ma A
classe et n'a repris que B
et C
qui sont sur lecom.xxx
package.
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 gardant les classes annotées A
, B
et C
et en ajoutant ce qui suit au XML, ce que nous obtiendrons après le chargement du contexte?
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Nous obtenons toujours le bon résultat:
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 pour la classe A
n'est pas obtenu par l'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 pourA
qui ont été enregistrés manuellement dans le XML.
Mais que se passe-t-il si nous avons le XML suivant, obtiendrons-nous des beans dupliqués parce que nous avons spécifié les deux <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 à nouveau 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 />
peuvent être omis si <context:component-scan>
spécifié), mais Spring se charge de les exécuter une seule fois.
Même si vous enregistrez vous-même les outils de traitement plusieurs fois, Spring s'assurera qu'ils ne font 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, ça parle de ça.
J'espère que ces informations ainsi que les réponses de @Tomasz Nurkiewicz et @Sean Patrick Floyd sont tout ce dont vous avez besoin pour comprendre comment
<context:annotation-config>
et <context:component-scan>
travailler.