Diferença entre <context: annotation-config> e <context: component-scan>

690

Estou aprendendo a Primavera 3 e não pareço entender a funcionalidade por trás <context:annotation-config>e <context:component-scan>.

Pelo que tenho lido eles parecem lidar com diferentes anotações ( @Required, @Autowiredetc vs @Component, @Repository, @Serviceetc), mas também pelo que tenho lido que registam os mesmos pós-processador de feijão classes.

Para me confundir ainda mais, existe um annotation-config atributo on <context:component-scan>.

Alguém pode lançar alguma luz sobre essas tags? O que é semelhante, o que é diferente, um é substituído pelo outro, eles se completam, eu preciso de um deles, ambos?

user938214097
fonte
para resumir: use component-scansempre que possível.
Jerry Chin

Respostas:

1419

<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, Be C, com Be Cser 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 bbbe cccno bean da seguinte Amaneira:

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 Atem pacote, com.yyymas eu especifiquei no <context:component-scan>pacote para usar, com.xxxentão isso perdeu completamente minha Aclasse e só foi atendida Be Cque está no com.xxxpacote.

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, Be Ce 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 Anã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 Aquais 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.


fonte
8
Citação: "<context: annotation-config /> pode ser omitido se <context: component-scan> for especificado". Por que usar a anotação-configuração então? Por que isso existe?
precisa saber é o seguinte
2
Ótima resposta! Nada como um pequeno exemplo claro com descrição concisa. Entendeu a coisa toda em uma leitura.
Jigish
19
Desejo que você tenha escrito o manual inteiro da Primavera! Melhor parte da explicação sobre qualquer coisa relacionada à confusão do Spring Framework. Obrigado.
precisa saber é o seguinte
7
Explicação tão simples e excelente. Ao lado de obter a resposta que eu também aprendi boa maneira de dizer as coisas :)
Amir Al
2
Seu estilo de escrita é muito fácil para um iniciante entender. Espero que você possa escrever um livro sobre a primavera básica. Eu prometo comprá-lo.
Emeraldhieu
167

Encontrei este belo resumo de quais anotações são captadas por quais declarações. Ao estudá-lo, você descobrirá que <context:component-scan/>reconhece um superconjunto de anotações reconhecidas por <context:annotation-config/>, a saber:

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

Como você pode ver, estende - se<context:component-scan/> logicamente com os recursos de varredura de componente CLASSPATH e Java @Configuration. <context:annotation-config/>

Tomasz Nurkiewicz
fonte
16
@Tomasz link down :(
Anand Rockzz
95

O Spring permite que você faça duas coisas:

  1. Fiação automática de feijão
  2. Descoberta automática de beans

1. Ligação automática
Normalmente, em applicationContext.xml, você define beans e outros beans são conectados usando métodos de construtor ou setter. Você pode conectar beans usando XML ou anotações. No caso de você usar anotações, você precisa anotações ativar e você tem que adicionar <context:annotation-config />em applicationContext.xml . Isso simplificará a estrutura da tag em applicationContext.xml , porque você não precisará conectar manualmente beans (construtor ou setter). Você pode usar @Autowireanotações e os beans serão conectados por tipo.

Um passo adiante para escapar da configuração XML manual é

2. Descoberta
Automática A descoberta automática está simplificando o XML um passo adiante, no sentido de que você nem precisa adicionar a <bean>tag no applicationContext.xml . Você acabou de marcar os beans específicos com uma das seguintes anotações e o Spring conectará automaticamente os beans marcados e suas dependências no contêiner do Spring. As anotações são as seguintes: @Controller , @Service , @Component , @Repository . Ao usar <context:component-scan>e apontar o pacote base, o Spring detectará e conectará automaticamente os componentes no contêiner do Spring.


Como uma conclusão:

  • <context:annotation-config />é usado para poder usar a anotação @Autowired
  • <context:component-scan /> é usado para determinar a pesquisa de beans específicos e a tentativa de fiação automática.
user2673474
fonte
1
É possível usar a varredura de componentes, mas não a anotação-configuração de alguma forma?
Koray Tugay
Use annotation-config = "false" no contexto: tag de anotação-configuração.
Sara
38

<context:annotation-config> ativa muitas anotações diferentes nos beans, sejam eles definidos em XML ou por meio da varredura de componentes.

<context:component-scan> é para definir beans sem usar XML

Para mais informações, leia:

Sean Patrick Floyd
fonte
Você pode explicar mais? Se eu usar <context:component-scan>, não poderei substituir a definição de bean usando XML?
user938214097
@ user938214097 você pode definir feijão tanto em XML ou através de anotações com digitalização componente
Sean Patrick Floyd
É suficiente usar o <context:component-scan>? Perco algo se não usar o <context:annotation-config>?
user938214097
@Tomasz parece ter respondido a essa
Sean Patrick Floyd
31

A diferença entre os dois é realmente simples!

<context:annotation-config /> 

Permite usar anotações restritas à ligação de propriedades e construtores apenas de beans !.

Enquanto que

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

Permite que tudo o que <context:annotation-config />pode fazer, com adição de usar estereótipos por exemplo .. @Component, @Service, @Repository. Assim, você pode conectar feijões inteiros e não apenas restritos a construtores ou propriedades !.

Sparticles
fonte
31

<context:annotation-config>: Digitalizando e ativando anotações para beans já registrados no xml de configuração da primavera.

<context:component-scan>: Registro de Bean +<context:annotation-config>


@Autowired e @Required são o nível de propriedade de destinos, portanto, o bean deve se registrar no COI da primavera antes de usar essas anotações. Para ativar essas anotações, é necessário registrar os respectivos beans ou incluir <context:annotation-config />. ou seja, <context:annotation-config />funciona apenas com beans registrados.

@Required ativa a RequiredAnnotationBeanPostProcessor ferramenta de processamento
@Autowired ativa a AutowiredAnnotationBeanPostProcessorferramenta de processamento

Nota: A anotação em si não tem nada a ver, precisamos de uma Ferramenta de processamento , que é uma classe abaixo, responsável pelo processo principal.


@Repository, @Service e @Controller são @Component e têm como alvo o nível de classe .

<context:component-scan>ele verifica o pacote e encontra e registra os beans, além de incluir o trabalho realizado por <context:annotation-config />.

Migrando XML para anotações

Premraj
fonte
15

A <context:annotation-config>tag diz ao Spring para varrer a base de código para resolver automaticamente os requisitos de dependência das classes que contêm a anotação @Autowired.

O Spring 2.5 também adiciona suporte para anotações JSR-250, como @Resource, @PostConstruct e @ PreDestroy. O uso dessas anotações também exige que determinados BeanPostProcessors sejam registrados no contêiner Spring. Como sempre, elas podem ser registradas como definições individuais de bean, mas também podem ser registradas implicitamente, incluindo a <context:annotation-config>tag na configuração da mola.

Retirado da documentação do Spring da Configuração baseada em anotação


O Spring fornece a capacidade de detectar automaticamente classes 'estereotipadas' e registrar as BeanDefinitions correspondentes no ApplicationContext.

De acordo com javadoc do org.springframework.stereotype :

Estereótipos são anotações que indicam as funções de tipos ou métodos na arquitetura geral (em um nível conceitual, e não de implementação). Exemplo: @Controller @Service @Repository etc. Estes destinam-se ao uso de ferramentas e aspectos (tornando um alvo ideal para pointcuts).

Para detectar automaticamente essas classes de 'estereótipo', <context:component-scan>é necessária uma tag.

A <context:component-scan>tag também diz ao Spring para verificar o código em busca de beans injetáveis ​​sob o pacote (e todos os seus subpacotes) especificados.

Sachin Sharma
fonte
14
<context:annotation-config>

Resolve apenas as anotações @Autowirede @Qualifer, isso é tudo, sobre a injeção de dependência . Existem outras anotações que fazem o mesmo trabalho, penso eu @Inject, mas estão prestes a resolver o DI por meio de anotações.

Esteja ciente de que, mesmo quando você declarou o <context:annotation-config>elemento, você deve declarar sua classe como um Bean de qualquer maneira, lembre-se de que temos três opções disponíveis

  • XML: <bean>
  • @ Anotações: @ Componente, @ Serviço, @ Repositório, @ Controlador
  • JavaConfig: @Configuração, @Bean

Agora com

<context:component-scan>

Faz duas coisas:

  • Ele varre todas as classes anotadas com @Component, @Service, @Repository, @Controller e @Configuration e cria um Bean
  • Faz o mesmo trabalho que <context:annotation-config>faz.

Portanto, se você declarar <context:component-scan>, não é mais necessário declarar <context:annotation-config>também.

Isso é tudo

Um cenário comum foi, por exemplo, declarar apenas um bean por meio de XML e resolver o DI por meio de anotações, por exemplo

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

Declaramos apenas os beans, nada sobre <constructor-arg>e <property>, o DI é configurado em suas próprias classes através do @Autowired. Significa que os Serviços usam @Autowired para seus componentes de Repositórios e os Repositórios usam @Autowired para os componentes JdbcTemplate, DataSource etc.

Manuel Jordan
fonte
1
excelente explicação Obrigado. @Manuel Jordan
BALS
7
<context:component-scan /> implicitly enables <context:annotation-config/>

tente com <context:component-scan base-package="..." annotation-config="false"/>, na sua configuração @ Service, @ Repository, @ Component funciona bem, mas @ Autowired, @ Resource e @Inject não funcionam.

Isso significa que AutowiredAnnotationBeanPostProcessor não será ativado e o contêiner Spring não processará as anotações de ligação automática.

Lovababu
fonte
Este me ajudou a entender que <context: component-scan /> implicitamente habilita <context: annotation-config />; ou seja, ele procura definições de bean e faz a injeção necessária. Eu experimentei o annotation-config = "false" e a injeção não funcionou, a menos que eu tenha definido explicitamente usando <context: annotation-config />. Finalmente, meu entendimento é melhor do que antes!
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. -->

O outro ponto importante a ser observado é que context:component-scanchama implicitamente o context:annotation-configpara ativar as anotações nos beans. Bem, se você não deseja context:component-scanativar implicitamente as anotações para você, pode continuar definindo o elemento de anotação-configuração do context:component-scanpara false.

Para resumir:

<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 -->
Abdullah Khan
fonte
1

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

Isso é usado para informar ao contêiner que existem classes de bean no meu pacote varrer essas classes de bean. Para varrer as classes de bean por contêiner em cima do bean, precisamos escrever uma anotação do tipo estéreo como a seguir.

@Component, @Service, @Repository,@Controller

<context:annotation-config />:

Se não queremos escrever uma tag de bean explicitamente em XML, como o contêiner sabe se há uma fiação automática no bean. Isso é possível usando a @Autowiredanotação. temos que informar ao contêiner que há fiação automática no meu bean context:annotation-config.

Pulipati Prasadarao
fonte
0

Uma <context:component-scan/>tag customizada registra o mesmo conjunto de definições de bean que é feito, além de sua principal responsabilidade de varrer os pacotes java e registrar definições de bean no caminho de classe.

Se, por algum motivo, esse registro das definições de bean padrão for evitado, a maneira de fazer isso é especificar um atributo "annotation-config" adicional na varredura de componentes, desta maneira:

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

Referência: http://www.java-allandsundry.com/2012/12/contextcomponent-scan-contextannotation.html

Abhishek Gaur
fonte
0

<context:annotation-config>:

Isso diz ao Spring que eu vou usar beans anotados como bean de primavera e eles seriam conectados através da @Autowiredanotação, em vez de declarar no arquivo xml de configuração do spring.

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

Isso informa ao contêiner do Spring, por onde começar a pesquisar esses beans anotados. Aqui, a primavera pesquisará todos os subpacotes do pacote base.

Sajal Chakraborty
fonte
0

você pode encontrar mais informações no arquivo de esquema de contexto da primavera. a seguir está em 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.
coffeenjava
fonte
0

Como complementar, você pode usar @ComponentScanpara usar <context:component-scan>em anotações.

Também é descrito em spring.io

Configura as diretivas de varredura de componentes para uso com as classes @Configuration. Fornece suporte paralelo ao elemento Spring XML.

Uma coisa a observar, se você estiver usando o Spring Boot, o @Configuration e o @ComponentScan podem ser implícitos usando a anotação @SpringBootApplication.

Eugene
fonte