Differenza tra <context: annotation-config> e <context: component-scan>


691

Sto imparando Spring 3 e non mi sembra di capire la funzionalità dietro <context:annotation-config>e <context:component-scan>.

Da quello che ho letto sembrano gestire diverse annotazioni ( @Required, @Autowiredecc vs @Component, @Repository, @Serviceecc), ma anche da quello che ho letto si registrano gli stessi post processore di fagioli classi.

Per confondermi ancora di più, c'è un annotation-config attributo su <context:component-scan>.

Qualcuno può fare luce su questi tag? Che cosa è simile, che cosa è diverso, l'uno è sostituito dall'altro, si completano a vicenda, ne ho bisogno uno di entrambi?



per riassumere: usare component-scanquando possibile.
Jerry Chin,

Risposte:


1420

<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, Be C, con Be Cdi 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à bbbe cccsul bean in questo Amodo:

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 Aha un pacchetto com.yyyma ho specificato nel <context:component-scan>pacchetto da usare, com.xxxquindi questo ha completamente perso la mia Aclasse e solo raccolto Be Cche sono sul com.xxxpacchetto.

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, Be Ce 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 Aquali è 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.


8
Citazione: "<context: annotation-config /> può essere omesso se si specifica <context: component-scan>". Perché mai usare annotation-config allora? Perché esiste?
CodeClimber

2
Bella risposta! Niente come un breve esempio chiaro con una descrizione concisa. Ho capito tutto in una lettura.
Jigish,

19
Vorrei che tu abbia scritto l'intero manuale di Spring! La migliore spiegazione su tutto ciò che riguarda confondere Spring Framework. Grazie.
eskalera,

7
Spiegazione così semplice ed eccezionale. Oltre a ottenere la risposta, ho anche imparato un buon modo per dire le cose :)
Amir Al

2
Il tuo stile di scrittura è molto facile da capire per un principiante. Spero che tu possa scrivere un libro sulla primavera di base. Prometto di acquistarlo.
emeraldhieu,

167

Ho trovato questo bel riassunto di quali annotazioni vengono raccolte da quali dichiarazioni. Studiandolo scoprirai che <context:component-scan/>riconosce un superset di annotazioni riconosciute da <context:annotation-config/>, vale a dire:

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

Come puoi vedere, si estende<context:component-scan/> logicamente con la scansione dei componenti CLASSPATH e le funzionalità Java @Configuration. <context:annotation-config/>


16
@Tomasz link down :(
Anand Rockzz

95

La primavera ti consente di fare due cose:

  1. Autowiring di fagioli
  2. Individuazione automatica dei fagioli

1. Autowiring
In genere in applicationContext.xml si definiscono bean e altri bean vengono cablati utilizzando i metodi di costruzione o setter. È possibile cablare i bean utilizzando XML o annotazioni. Nel caso in cui si utilizzano le annotazioni, è necessario attivare e annotazioni si deve aggiungere <context:annotation-config />in applicationContext.xml . Ciò semplificherà la struttura del tag da applicationContext.xml , poiché non sarà necessario cablare manualmente i bean (costruttore o setter). È possibile utilizzare l' @Autowireannotazione e i bean verranno cablati per tipo.

Un passo avanti per sfuggire alla configurazione XML manuale è

2. Individuazione automatica L'individuazione
automatica sta semplificando ulteriormente l'XML, nel senso che non è nemmeno necessario aggiungere il <bean>tag in applicationContext.xml . È sufficiente contrassegnare i bean specifici con una delle seguenti annotazioni e Spring collegherà automaticamente i bean contrassegnati e le relative dipendenze nel contenitore Spring. Le annotazioni sono le seguenti: @Controller , @Service , @Component , @Repository . Usando <context:component-scan>e indicando il pacchetto base, Spring rileverà automaticamente e collegherà i componenti nel contenitore Spring.


Come conclusione:

  • <context:annotation-config />viene utilizzato per poter utilizzare l' annotazione @Autowired
  • <context:component-scan /> viene utilizzato per determinare la ricerca di bean specifici e il tentativo di autowiring.

1
È possibile utilizzare la scansione dei componenti ma non la configurazione delle annotazioni in qualche modo?
Koray Tugay,

Usa annotation-config = "false" nel contesto: tag annotation-config.
Sara,

38

<context:annotation-config> attiva molte diverse annotazioni nei bean, siano esse definite in XML o attraverso la scansione dei componenti.

<context:component-scan> serve per definire i bean senza usare XML

Per ulteriori informazioni, leggi:


Puoi per favore spiegare ulteriormente? Se uso <context:component-scan>non sarò in grado di sovrascrivere la definizione del bean usando XML?
user938214097

@ user938214097 è possibile definire bean in XML o tramite annotazioni con scansione dei componenti
Sean Patrick Floyd

È sufficiente usare il <context:component-scan>? Perdo qualcosa se non uso <context:annotation-config>?
user938214097

@Tomasz sembra aver risposto che
Sean Patrick Floyd,

31

La differenza tra i due è davvero semplice !.

<context:annotation-config /> 

Consente di utilizzare le annotazioni limitate al cablaggio di proprietà e costruttori solo di bean !.

Mentre

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

Abilita tutto ciò che <context:annotation-config />può fare, con l'aggiunta di utilizzare stereotipi per esempio .. @Component, @Service, @Repository. Quindi puoi cablare interi bean e non limitarti a costruttori o proprietà !.


31

<context:annotation-config>: Scansione e attivazione di annotazioni per bean già registrati in XML config di primavera.

<context:component-scan>: Registrazione del fagiolo +<context:annotation-config>


@Autowired e @Required sono target livello di proprietà, quindi il bean dovrebbe registrarsi in IOC prima di usare queste annotazioni. Per abilitare queste annotazioni, è necessario registrare i rispettivi bean o includere <context:annotation-config />. cioè <context:annotation-config />funziona solo con bean registrati.

@Required abilita lo RequiredAnnotationBeanPostProcessor strumento di elaborazione
@Autowired abilita lo AutowiredAnnotationBeanPostProcessorstrumento di elaborazione

Nota: l' annotazione stessa non ha nulla da fare, abbiamo bisogno di uno strumento di elaborazione , che è una classe sottostante, responsabile del processo principale.


@Repository, @Service e @Controller sono @Component e hanno come target il livello di classe .

<context:component-scan>esegue la scansione del pacchetto, trova e registra i bean e include il lavoro svolto da <context:annotation-config />.

Migrazione da XML a annotazioni


15

Il <context:annotation-config>tag dice a Spring di scansionare la base di codice per risolvere automaticamente i requisiti di dipendenza delle classi contenenti l'annotazione @Autowired.

Spring 2.5 aggiunge anche il supporto per le annotazioni JSR-250 come @Resource, @PostConstruct e @ PreDestroy. L'uso di queste annotazioni richiede anche che determinati processori BeanPost siano registrati nel contenitore Spring. Come sempre, questi possono essere registrati come definizioni di singoli bean, ma possono anche essere implicitamente registrati includendo<context:annotation-config> tag nella configurazione di primavera.

Tratto dalla documentazione di Spring sulla configurazione basata su annotazioni


Spring offre la capacità di rilevare automaticamente classi "stereotipate" e di registrare le definizioni Bean corrispondenti con ApplicationContext.

Secondo javadoc di org.springframework.stereotype :

Gli stereotipi sono annotazioni che indicano i ruoli di tipi o metodi nell'architettura complessiva (a livello concettuale, piuttosto che di implementazione). Esempio: @Controller @Service @Repository ecc. Questi sono destinati all'uso da parte di strumenti e aspetti (che rappresentano un obiettivo ideale per i tagli di punti).

Per rilevare automaticamente tali classi di "stereotipi", <context:component-scan>è richiesto il tag.

Il <context:component-scan>tag dice anche a Spring di scansionare il codice alla ricerca di bean iniettabili sotto il pacchetto (e tutti i suoi sotto-pacchetti) specificati.


14
<context:annotation-config>

Risolve solo le annotazioni @Autowirede @Qualifer, tutto qui, riguardo all'iniezione delle dipendenze , ci sono altre annotazioni che fanno lo stesso lavoro, penso come@Inject , ma tutto per risolvere il DI attraverso le annotazioni.

Fai attenzione, anche quando hai dichiarato l' <context:annotation-config>elemento, devi dichiarare la tua classe come un fagiolo comunque, ricorda che abbiamo tre opzioni disponibili

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

Adesso con

<context:component-scan>

Fa due cose:

  • Esegue la scansione di tutte le classi annotate con @Component, @Service, @Repository, @Controller e @Configuration e crea un bean
  • Fa lo stesso lavoro come <context:annotation-config>fa.

Pertanto, se si dichiara <context:component-scan>, non è più necessario dichiarare<context:annotation-config> anche.

È tutto

Uno scenario comune era ad esempio dichiarare solo un bean tramite XML e risolvere il DI tramite annotazioni, ad esempio

<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" />

Abbiamo dichiarato solo i bean, nulla <constructor-arg>e <property>il DI è configurato nelle proprie classi tramite @Autowired. Significa che i Servizi utilizzano @Autowired per i componenti dei loro repository e che i Repository utilizzano @Autowired per i componenti JdbcTemplate, DataSource ecc.


1
spiegazione superba Grazie. @Manuel Jordan
BALS

7
<context:component-scan /> implicitly enables <context:annotation-config/>

prova con <context:component-scan base-package="..." annotation-config="false"/>, nella tua configurazione @Service, @Repository, @Component funziona bene, ma @ Autowired, @ Resource e @Inject non funzionano.

Ciò significa che AutowiredAnnotationBeanPostProcessor non sarà abilitato e il contenitore Spring non elaborerà le annotazioni di Autowiring.


Questo mi ha aiutato a capire che <context: component-scan /> abilita implicitamente <context: annotation-config />; cioè cerca le definizioni dei bean e fa l'iniezione necessaria. Ho sperimentato annotation-config = "false" e l'iniezione non ha funzionato a meno che non abbia impostato esplicitamente usando <context: annotation-config />. Finalmente la mia comprensione è migliore di prima!
CuriousMind

5
<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'altro punto importante da notare è che context:component-scanchiama implicitamente il context:annotation-configper attivare le annotazioni sui bean. Bene, se non vuoi context:component-scanattivare implicitamente le annotazioni per te, puoi continuare a impostare l'elemento annotation-config del context:component-scanto false.

Riassumere:

<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 -->

1

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

Questo è usato per dire al contenitore che ci sono classi bean nel mio pacchetto scansionare quelle classi bean. Per scansionare le classi di bean per contenitore sopra il bean, dobbiamo scrivere una delle annotazioni di tipo stereo come segue.

@Component, @Service, @Repository,@Controller

<context:annotation-config />:

Se non vogliamo scrivere in modo esplicito tag bean in XML, come il contenitore sa se esiste un cablaggio automatico nel bean. Ciò è possibile utilizzando l' @Autowiredannotazione. dobbiamo informare il container che è presente un cablaggio automatico nel mio bean context:annotation-config.


0

Un <context:component-scan/>tag personalizzato registra la stessa serie di definizioni bean che viene eseguita, a parte la sua responsabilità primaria di scansionare i pacchetti java e registrare le definizioni bean dal percorso di classe.

Se per qualche motivo questa registrazione delle definizioni dei bean predefiniti deve essere evitata, il modo per farlo è quello di specificare un attributo "annotation-config" aggiuntivo nella scansione dei componenti, in questo modo:

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

Riferimento: http://www.java-allandsundry.com/2012/12/contextcomponent-scan-contextannotation.html


0

<context:annotation-config>:

Questo dice a Spring che userò i fagioli annotati come fagiolini e che verrebbero cablati @Autowired annotazione, invece di dichiarare nel file xml di configurazione della primavera.

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

Questo dice al contenitore Spring, da dove iniziare la ricerca di quei bean annotati. Qui la primavera cercherà tutti i sotto-pacchetti del pacchetto base.


0

puoi trovare maggiori informazioni nel file di schema del contesto di primavera. di seguito è riportato in spring-context-4.3.xsd

<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

Come complemento, è possibile utilizzare @ComponentScanper utilizzare <context:component-scan>in modo annotazione.

È anche descritto su spring.io

Configura le direttive di scansione dei componenti per l'uso con le classi @Configuration. Fornisce supporto in parallelo con l'elemento Spring XML.

Una cosa da notare, se si utilizza Spring Boot, @Configuration e @ComponentScan possono essere impliciti utilizzando l'annotazione @SpringBootApplication.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.