<context:annotation-config>
é usado para ativar anotações em beans já registrados no contexto do aplicativo (não importa se eles foram definidos com XML ou pela varredura de pacote).
<context:component-scan>
também pode fazer o que <context:annotation-config>
faz, mas <context:component-scan>
também verifica os pacotes para localizar e registrar beans no contexto do aplicativo.
Vou usar alguns exemplos para mostrar as diferenças / semelhanças.
Permite começar com uma configuração básica de três grãos de tipo A
, B
e C
, com B
e C
ser injectado 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;
}
}
Com a seguinte configuração 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>
Carregar o contexto produz a seguinte saída:
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, esta é a saída esperada. Mas este é o "estilo antigo" da primavera. Agora temos anotações, então vamos usá-las para simplificar o XML.
Primeiro, vamos autorizar as propriedades bbb
e ccc
no bean da seguinte A
maneira:
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;
}
}
Isso permite remover as seguintes linhas do XML:
<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />
Meu XML agora está simplificado para isso:
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />
Quando carrego o contexto, recebo a seguinte saída:
creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf
OK, isso está errado! O que aconteceu? Por que minhas propriedades não são conectadas automaticamente?
Bem, as anotações são um recurso interessante, mas elas mesmas não fazem nada. Eles apenas anotam coisas. Você precisa de uma ferramenta de processamento para encontrar as anotações e fazer algo com elas.
<context:annotation-config>
para o resgate. Isso ativa as ações para as anotações encontradas nos beans definidos no mesmo contexto do aplicativo em que ele próprio está definido.
Se eu mudar meu XML para isso:
<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 carrego o contexto do aplicativo, obtenho o resultado adequado:
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, isso é legal, mas removi duas linhas do XML e adicionei uma. Essa não é uma grande diferença. A idéia com anotações é que ela deve remover o XML.
Então, vamos remover as definições XML e substituí-las por anotações:
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;
}
}
Enquanto no XML, mantemos apenas isso:
<context:annotation-config />
Carregamos o contexto e o resultado é ... Nada. Nenhum bean é criado, nenhum bean é conectado automaticamente. Nada!
Isso porque, como eu disse no primeiro parágrafo, o <context:annotation-config />
único funciona em beans registrados no contexto do aplicativo. Como eu removi a configuração XML dos três beans, ele não é criado e <context:annotation-config />
não possui "destinos" para trabalhar.
Mas isso não será um problema para o <context:component-scan>
qual é possível digitalizar um pacote em busca de "destinos". Vamos mudar o conteúdo da configuração XML para a seguinte entrada:
<context:component-scan base-package="com.xxx" />
Quando carrego o contexto, recebo a seguinte saída:
creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff
Hmmmm ... algo está faltando. Por quê?
Se você olhar de perto para as classes, a classe A
tem pacote, com.yyy
mas eu especifiquei no <context:component-scan>
pacote para usar, com.xxx
então isso perdeu completamente minha A
classe e só foi atendida B
e C
que está no com.xxx
pacote.
Para corrigir isso, adiciono este outro pacote também:
<context:component-scan base-package="com.xxx,com.yyy" />
e agora obtemos o resultado esperado:
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 é isso! Agora você não tem mais definições XML, possui anotações.
Como exemplo final, mantendo as classes anotadas A
, B
e C
e adicionando o seguinte ao XML, o que nós vamos ter depois de carregar o contexto?
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Ainda obtemos o resultado correto:
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
Mesmo que o bean da classe A
não seja obtido pela varredura, as ferramentas de processamento ainda serão aplicadas <context:component-scan>
em todos os beans registrados no contexto do aplicativo, mesmo para os A
quais foram registrados manualmente no XML.
Mas e se tivermos o XML a seguir, obteremos beans duplicados porque especificamos ambos <context:annotation-config />
e <context:component-scan>
?
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />
Não, sem duplicações, novamente obtemos o resultado esperado:
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
Isso ocorre porque as duas tags registram as mesmas ferramentas de processamento ( <context:annotation-config />
podem ser omitidas se <context:component-scan>
for especificado), mas o Spring cuida de executá-las apenas uma vez.
Mesmo se você registrar as ferramentas de processamento várias vezes, o Spring ainda garantirá que elas façam a mágica apenas uma vez; este 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" />
ainda gerará o seguinte resultado:
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, é sobre o rap.
Espero que essas informações, juntamente com as respostas de @Tomasz Nurkiewicz e @Sean Patrick Floyd, sejam tudo o que você precisa para entender como
<context:annotation-config>
e <context:component-scan>
trabalhar.