<context:annotation-config>
viene utilizzato per attivare le annotazioni nei bean già registrati nel contesto dell'applicazione (indipendentemente dal fatto che siano stati definiti con XML o mediante scansione del pacchetto).
<context:component-scan>
può anche fare ciò che <context:annotation-config>
fa, ma <context:component-scan>
scansiona anche i pacchetti per trovare e registrare bean nel contesto dell'applicazione.
Userò alcuni esempi per mostrare le differenze / somiglianze.
Consente di iniziare con una configurazione di base di tre chicchi di tipo A
, B
e C
, con B
e C
di essere iniettato in 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;
}
}
Con la seguente configurazione XML:
<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>
Il caricamento del contesto produce il seguente output:
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, questo è l'output previsto. Ma questa è la primavera "vecchio stile". Ora abbiamo annotazioni, quindi usiamole per semplificare l'XML.
Innanzitutto, autorizza le proprietà bbb
e ccc
sul bean in questo A
modo:
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;
}
}
Questo mi permette di rimuovere le seguenti righe dall'XML:
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
Il mio XML è ora semplificato a questo:
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
Quando carico il contesto ottengo il seguente output:
creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf
OK, questo è sbagliato! Quello che è successo? Perché le mie proprietà non sono autowired?
Bene, le annotazioni sono una bella caratteristica ma da sole non fanno nulla. Annotano solo cose. È necessario uno strumento di elaborazione per trovare le annotazioni e fare qualcosa con esse.
<context:annotation-config>
Al salvataggio. Ciò attiva le azioni per le annotazioni che trova sui bean definiti nello stesso contesto dell'applicazione in cui è definito.
Se cambio il mio XML in questo:
<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
quando carico il contesto dell'applicazione ottengo il risultato corretto:
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, questo è carino, ma ho rimosso due file dall'XML e ne ho aggiunto uno. Questa non è una grande differenza. L'idea con le annotazioni è che dovrebbe rimuovere l'XML.
Quindi rimuoviamo le definizioni XML e sostituirle tutte con le annotazioni:
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;
}
}
Mentre nell'XML manteniamo solo questo:
<context:annotation-config />
Carichiamo il contesto e il risultato è ... Niente. Nessun bean creato, nessun bean autowired. Niente!
Questo perché, come ho detto nel primo paragrafo, <context:annotation-config />
funziona solo su bean registrati nel contesto dell'applicazione. Poiché ho rimosso la configurazione XML per i tre bean, non è stato creato alcun bean e <context:annotation-config />
non ha "target" su cui lavorare.
Ma questo non sarà un problema per il <context:component-scan>
quale è possibile eseguire la scansione di un pacchetto per "obiettivi" su cui lavorare. Cambiamo il contenuto della configurazione XML nella seguente voce:
<context:component-scan base-package="com.xxx" />
Quando carico il contesto ottengo il seguente output:
creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff
Hmmmm ... manca qualcosa. Perché?
Se guardi da vicino le classi, la classe A
ha un pacchetto com.yyy
ma ho specificato nel <context:component-scan>
pacchetto da usare, com.xxx
quindi questo ha completamente perso la mia A
classe e solo raccolto B
e C
che sono sul com.xxx
pacchetto.
Per risolvere questo problema, aggiungo anche questo altro pacchetto:
<context:component-scan base-package="com.xxx,com.yyy" />
e ora otteniamo il risultato atteso:
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
E questo è tutto! Ora non hai più definizioni XML, hai annotazioni.
Come esempio finale, mantenendo le classi annotate A
, B
e C
e aggiungendo la seguente al codice XML, che cosa otterremo dopo aver caricato il contesto?
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Otteniamo ancora il risultato corretto:
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
Anche se il fagiolo per la classe A
non viene ottenuto mediante la scansione, gli strumenti di elaborazione vengono comunque applicati da <context:component-scan>
tutti i bean registrati nel contesto dell'applicazione, anche per i A
quali è stato registrato manualmente nell'XML.
E se avessimo il seguente XML, otterremo bean duplicati perché abbiamo specificato sia <context:annotation-config />
e <context:component-scan>
?
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
No, nessuna duplicazione, otteniamo ancora il risultato atteso:
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
Questo perché entrambi i tag registrano gli stessi strumenti di elaborazione (<context:annotation-config />
può essere omesso se <context:component-scan>
specificato), ma Spring si occupa di eseguirli una sola volta.
Anche se registri tu stesso gli strumenti di elaborazione più volte, Spring farà comunque in modo che facciano la loro magia una sola volta; questo 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" />
genererà comunque il seguente risultato:
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, questo riguarda il rap.
Spero che queste informazioni insieme alle risposte di @Tomasz Nurkiewicz e @Sean Patrick Floyd siano tutto ciò che serve per capire come <context:annotation-config>
e come
<context:component-scan>
lavorare.