Diferencia entre <context: annotation-config> y <context: component-scan>

691

Estoy aprendiendo Spring 3 y parece que no entiendo la funcionalidad detrás <context:annotation-config>y <context:component-scan>.

Por lo que he leído parece que manejar diferentes anotaciones ( @Required, @Autowiredetc vs @Component, @Repository, @Serviceetc), sino también de lo que he leído se registran los mismos postprocesador frijol clases.

Para confundirme aún más, hay un annotation-config atributo activado <context:component-scan>.

¿Alguien puede arrojar algo de luz sobre estas etiquetas? Lo que es similar, lo que es diferente, es uno reemplazado por el otro, se completan, ¿necesito uno de los dos?

usuario938214097
fuente
55
techidiocy.com/annotation-config-vs-component-scan-spring-core aquí hay una explicación brillante
VdeX
para resumir: usar component-scansiempre que sea posible.
Jerry Chin

Respuestas:

1420

<context:annotation-config> se utiliza para activar anotaciones en beans ya registrados en el contexto de la aplicación (sin importar si se definieron con XML o mediante escaneo de paquetes).

<context:component-scan>También puede hacer lo que <context:annotation-config>hace, pero <context:component-scan>también escanea paquetes para buscar y registrar beans dentro del contexto de la aplicación.

Usaré algunos ejemplos para mostrar las diferencias / similitudes.

Comencemos con una configuración básica de tres beans de tipo A, By C, con By Csiendo inyectado 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 siguiente configuración 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>

Cargar el contexto produce el siguiente resultado:

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, este es el resultado esperado. Pero este es el "viejo estilo" de primavera. Ahora tenemos anotaciones, así que usemos esas para simplificar el XML.

Primero, vamos a conectar automáticamente las propiedades bbby cccen bean Aasí:

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

Esto me permite eliminar las siguientes filas del XML:

<property name="bbb" ref="bBean" />
<property name="ccc" ref="cBean" />

Mi XML ahora está simplificado a esto:

<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

Cuando cargo el contexto obtengo el siguiente resultado:

creating bean B: com.xxx.B@5e5a50
creating bean C: com.xxx.C@54a328
creating bean A: com.yyy.A@a3d4cf

OK, esto está mal! ¿Que pasó? ¿Por qué mis propiedades no tienen cableado automático?

Bueno, las anotaciones son una buena característica, pero por sí mismas no hacen nada en absoluto. Simplemente anotan cosas. Necesita una herramienta de procesamiento para encontrar las anotaciones y hacer algo con ellas.

<context:annotation-config>al rescate. Esto activa las acciones para las anotaciones que encuentra en los beans definidos en el mismo contexto de aplicación donde se define.

Si cambio mi XML a esto:

<context:annotation-config />
<bean id="bBean" class="com.xxx.B" />
<bean id="cBean" class="com.xxx.C" />
<bean id="aBean" class="com.yyy.A" />

cuando cargo el contexto de la aplicación obtengo el resultado correcto:

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, esto es bueno, pero eliminé dos filas del XML y agregué una. Esa no es una gran diferencia. La idea con anotaciones es que se supone que elimina el XML.

Así que eliminemos las definiciones XML y las reemplacemos todas con anotaciones:

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

Mientras que en el XML solo guardamos esto:

<context:annotation-config />

Cargamos el contexto y el resultado es ... Nada. No se crean beans, no hay beans con conexión automática. ¡Nada!

Eso es porque, como dije en el primer párrafo, el <context:annotation-config />único funciona en beans registrados dentro del contexto de la aplicación. Debido a que eliminé la configuración XML para los tres beans, no se creó ningún bean y <context:annotation-config />no tiene "objetivos" para trabajar.

Pero ese no será un problema para el <context:component-scan>que pueda escanear un paquete en busca de "objetivos" para trabajar. Cambiemos el contenido de la configuración XML a la siguiente entrada:

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

Cuando cargo el contexto obtengo el siguiente resultado:

creating bean B: com.xxx.B@1be0f0a
creating bean C: com.xxx.C@80d1ff

Hmmmm ... falta algo. ¿Por qué?

Si miras de cerca las clases, la clase Atiene un paquete, com.yyypero he especificado en el <context:component-scan>paquete para usar, com.xxxasí que esto perdió por completo mi Aclase y solo recogió By Cque están en el com.xxxpaquete.

Para solucionar esto, agrego este otro paquete también:

<context:component-scan base-package="com.xxx,com.yyy" />

y ahora obtenemos el 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

¡Y eso es! Ahora ya no tiene definiciones XML, tiene anotaciones.

Como ejemplo final, manteniendo las clases anotadas A, By Cy añadiendo lo siguiente en el XML, lo que vamos a llegar después de cargar el contexto?

<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

Aún obtenemos el resultado correcto:

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

Incluso si el bean para la clase Ano se obtiene escaneando, las herramientas de procesamiento todavía se aplican <context:component-scan>en todos los beans registrados en el contexto de la aplicación, incluso para los Aque se registraron manualmente en el XML.

Pero, ¿qué pasa si tenemos el siguiente XML? ¿Obtendremos beans duplicados porque hemos especificado ambos <context:annotation-config />y <context:component-scan>?

<context:annotation-config />
<context:component-scan base-package="com.xxx" />
<bean id="aBean" class="com.yyy.A" />

No, no hay duplicaciones, nuevamente obtenemos el 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

Esto se debe a que ambas etiquetas registran las mismas herramientas de procesamiento ( <context:annotation-config />se pueden omitir si <context:component-scan>se especifica), pero Spring se encarga de ejecutarlas solo una vez.

Incluso si registra las herramientas de procesamiento usted mismo varias veces, Spring se asegurará de que hagan su magia solo una 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" />

seguirá generando el siguiente 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

De acuerdo, eso es todo.

Espero que esta información junto con las respuestas de @Tomasz Nurkiewicz y @Sean Patrick Floyd sean todo lo que necesita para entender cómo <context:annotation-config>y <context:component-scan>trabajar.


fuente
8
Cita: "<context: annotation-config /> se puede omitir si se especifica <context: component-scan>". ¿Por qué usar annotation-config entonces? ¿Por qué existe?
CodeClimber
2
¡Gran respuesta! Nada como un breve ejemplo claro con una descripción concisa. Entendí todo en una lectura.
Jigish
19
¡Deseo que escribiste todo el manual de Spring! La mejor explicación sobre cualquier cosa relacionada con la confusa Spring Framework. Gracias.
eskalera
77
Tan simple y sobresaliente explicación. Además de obtener la respuesta, también aprendí una buena manera de contar las cosas :)
Amir Al
2
Su estilo de escritura es muy fácil de entender para un principiante. Espero que puedas escribir un libro sobre Spring básico. Prometo comprarlo.
emeraldhieu
167

Encontré este bonito resumen de qué anotaciones son recogidas por qué declaraciones. Al estudiarlo, encontrará que <context:component-scan/>reconoce un superconjunto de anotaciones reconocidas por <context:annotation-config/>, a saber:

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

Como puede ver, <context:component-scan/>lógicamente se extiende <context:annotation-config/> con el escaneo de componentes CLASSPATH y las características de Java @Configuration.

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

Spring te permite hacer dos cosas:

  1. Autowiring de frijoles
  2. Descubrimiento automático de frijoles

1. Autowiring
Por lo general, en applicationContext.xml se definen beans y otros beans se cablean utilizando métodos de construcción o configuración. Puede conectar beans utilizando XML o anotaciones. En caso de que utilice anotaciones, es necesario activar y anotaciones que hay que añadir <context:annotation-config />en applicationContext.xml . Esto simplificará la estructura de la etiqueta desde applicationContext.xml , ya que no tendrá que cablear manualmente beans (constructor o setter). Puede usar la @Autowireanotación y los beans se cablearán por tipo.

Un paso adelante para escapar de la configuración manual de XML es

2. Detección
automática La detección automática está simplificando el XML un paso más, en el sentido de que ni siquiera necesita agregar la <bean>etiqueta en applicationContext.xml . Simplemente marque los beans específicos con una de las siguientes anotaciones y Spring conectará automáticamente los beans marcados y sus dependencias al contenedor Spring. Las anotaciones son las siguientes: @Controller , @Service , @Component , @Repository . Al usar <context:component-scan>y señalar el paquete base, Spring detectará automáticamente y conectará los componentes al contenedor Spring.


Como conclusión:

  • <context:annotation-config />se usa para poder usar la anotación @Autowired
  • <context:component-scan /> se usa para determinar la búsqueda de beans específicos y el intento de autoconexión.
usuario2673474
fuente
1
¿Es posible usar el escaneo de componentes pero no la configuración de anotación de alguna manera?
Koray Tugay
Utilice annotation-config = "false" en contexto: annotation-config tag.
Sara
38

<context:annotation-config> activa muchas anotaciones diferentes en beans, ya sea que estén definidas en XML o mediante escaneo de componentes.

<context:component-scan> es para definir beans sin usar XML

Para más información, lea:

Sean Patrick Floyd
fuente
¿Puedes por favor explicar más? Si lo uso <context:component-scan>, ¿no podré anular la definición de bean usando XML?
user938214097
@ user938214097 puede definir beans en XML o mediante anotaciones con escaneo de componentes
Sean Patrick Floyd
¿Es suficiente usar el <context:component-scan>? ¿Pierdo algo si no uso el <context:annotation-config>?
user938214097
@Tomasz parece haber respondido eso
Sean Patrick Floyd
31

¡La diferencia entre los dos es realmente simple!

<context:annotation-config /> 

Le permite usar anotaciones que están restringidas al cableado de propiedades y constructores solo de beans.

Donde como

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

Permite todo lo que <context:annotation-config />puede hacer, con la adición de la utilización de estereotipos por ejemplo, .. @Component, @Service, @Repository. ¡Para que pueda conectar frijoles enteros y no solo restringidos a constructores o propiedades!

Espartículas
fuente
31

<context:annotation-config>: Escaneo y activación de anotaciones para beans ya registrados en spring config xml.

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


@Autowired y @Required son el nivel de propiedad de destino, por lo que el bean debe registrarse en el IOC de primavera antes de usar estas anotaciones. Para habilitar estas anotaciones, debe registrar los respectivos beans o incluir <context:annotation-config />. es decir, solo <context:annotation-config />funciona con beans registrados.

@Required habilita la RequiredAnnotationBeanPostProcessor herramienta de procesamiento
@Autowired habilita la AutowiredAnnotationBeanPostProcessorherramienta de procesamiento

Nota: la anotación en sí no tiene nada que ver, necesitamos una herramienta de procesamiento , que es una clase debajo, responsable del proceso central.


@Repository, @Service y @Controller son @Component , y se dirigen a nivel de clase .

<context:component-scan>escanea el paquete y busca y registra los beans, e incluye el trabajo realizado por <context:annotation-config />.

Migración de XML a anotaciones

Premraj
fuente
15

La <context:annotation-config>etiqueta le dice a Spring que escanee la base de código para resolver automáticamente los requisitos de dependencia de las clases que contienen la anotación @Autowired.

Spring 2.5 también agrega soporte para anotaciones JSR-250 como @Resource, @PostConstruct y @ PreDestroy. El uso de estas anotaciones también requiere que ciertos BeanPostProcessors se registren dentro del contenedor Spring. Como siempre, estos se pueden registrar como definiciones de beans individuales, pero también se pueden registrar implícitamente al incluir la <context:annotation-config>etiqueta en la configuración de primavera.

Tomado de la documentación de Spring de la configuración basada en anotaciones


Spring proporciona la capacidad de detectar automáticamente clases 'estereotipadas' y registrar las definiciones de Bean correspondientes con el ApplicationContext.

Según el javadoc de org.springframework.stereotype :

Los estereotipos son anotaciones que denotan los roles de los tipos o métodos en la arquitectura general (a nivel conceptual, en lugar de implementación). Ejemplo: @Controller @Service @Repository, etc. Están destinados a ser utilizados por herramientas y aspectos (lo que constituye un objetivo ideal para los puntos de corte).

Para autodetectar tales clases de 'estereotipo', <context:component-scan>se requiere etiqueta.

La <context:component-scan>etiqueta también le dice a Spring que escanee el código en busca de granos inyectables debajo del paquete (y todos sus subpaquetes) especificados.

Sachin Sharma
fuente
14
<context:annotation-config>

Solo resuelve las anotaciones @Autowiredy @Qualifer, eso es todo, se trata de la inyección de dependencia , hay otras anotaciones que hacen el mismo trabajo, creo que cómo @Inject, pero todo a punto de resolver DI a través de anotaciones.

Tenga en cuenta que, incluso cuando haya declarado el <context:annotation-config>elemento, debe declarar a su clase como un Bean de todos modos, recuerde que tenemos tres opciones disponibles

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

Ahora con

<context:component-scan>

Hace dos cosas:

  • Escanea todas las clases anotadas con @Component, @Service, @Repository, @Controller y @Configuration y crea un Bean
  • Hace el mismo trabajo como lo <context:annotation-config>hace.

Por lo tanto, si declaras <context:component-scan>, ya no es necesario declarar <context:annotation-config>también.

Eso es todo

Un escenario común era, por ejemplo, declarar solo un bean a través de XML y resolver el DI a través de anotaciones, por ejemplo

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

Solo hemos declarado los beans, nada al respecto , <constructor-arg>y <property>el DI está configurado en sus propias clases a través de @Autowired. Significa que los Servicios usan @Autowired para sus componentes de Repositorios y los Repositorios usan @Autowired para los componentes JdbcTemplate, DataSource, etc.

Manuel Jordan
fuente
1
excelente explicación Gracias. @Manuel Jordan
BALS
7
<context:component-scan /> implicitly enables <context:annotation-config/>

intente con <context:component-scan base-package="..." annotation-config="false"/>, en su configuración @Service, @Repository, @Component funciona bien, pero @ Autowired, @ Resource y @Inject no funcionan.

Esto significa que AutowiredAnnotationBeanPostProcessor no estará habilitado y Spring container no procesará las anotaciones de Autowiring.

Lovababu
fuente
Este me ayudó a comprender que <context: component-scan /> implícitamente habilita <context: annotation-config />; es decir, escanea las definiciones de frijoles y la inyección necesaria. Experimenté con annotation-config = "false", y la inyección no funcionó a menos que establezca explícitamente usando <context: annotation-config />. ¡Finalmente mi comprensión es mejor 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. -->

El otro punto importante a tener en cuenta es que context:component-scanllama implícitamente context:annotation-configa activar las anotaciones en beans. Bueno, si no desea context:component-scanactivar anotaciones implícitamente para usted, puede continuar configurando el elemento annotation-config de context:component-scanto 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
fuente
1

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

Esto se usa para decirle al contenedor que hay clases de bean en mi paquete, escanee esas clases de bean. Para escanear clases de bean por contenedor en la parte superior del bean, tenemos que escribir una de las anotaciones de tipo estéreo como la siguiente.

@Component, @Service, @Repository,@Controller

<context:annotation-config />:

Si no queremos escribir la etiqueta del bean explícitamente en XML, entonces cómo el contenedor sabe si hay un cableado automático en el bean. Esto es posible mediante el uso de @Autowiredanotaciones. Tenemos que informar al contenedor que hay un cableado automático en mi bean context:annotation-config.

Pulipati Prasadarao
fuente
0

Una <context:component-scan/>etiqueta personalizada registra el mismo conjunto de definiciones de bean que se realiza, aparte de su responsabilidad principal de escanear los paquetes de Java y registrar las definiciones de bean desde el classpath.

Si por alguna razón se evita este registro de definiciones de bean predeterminadas, la forma de hacerlo es especificar un atributo adicional "annotation-config" en el escaneo de componentes, de esta manera:

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

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

Abhishek Gaur
fuente
0

<context:annotation-config>:

Esto le dice a Spring que voy a usar frijoles anotados como spring bean y que se conectarán a través de @Autowiredanotaciones, en lugar de declarar en el archivo Spring config xml.

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

Esto le dice al contenedor Spring, dónde comenzar a buscar esos granos anotados. Aquí la primavera buscará todos los subpaquetes del paquete base.

Sajal Chakraborty
fuente
0

puede encontrar más información en el archivo de esquema de contexto de primavera. siguiente está en 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
fuente
0

Como complemento, puede usarlo @ComponentScanpara usarlo <context:component-scan>en forma de anotación.

También se describe en spring.io

Configura directivas de escaneo de componentes para usar con las clases de @Configuration. Proporciona soporte paralelo con el elemento Spring XML.

Una cosa a tener en cuenta, si está utilizando Spring Boot, @Configuration y @ComponentScan pueden implicarse mediante el uso de la anotación @SpringBootApplication.

Eugene
fuente