Pregunta Diferencia entre vs


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

Por lo que he leído, parecen manejar anotaciones diferentes (@Required, @Autowired etc vs @Component, @Repository, @Service, etc.) pero también de lo que he leído, registran las mismas clases de bean post processor.

Para confundirme aún más, hay un annotation-config atributo en <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 el uno al otro, ¿necesito uno de ellos, ambos?


609
2017-09-14 10:28


origen


Respuestas:


<context:annotation-config> se usa 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> pero <context:component-scan> también escanea paquetes para encontrar y registrar frijoles dentro del contexto de la aplicación.

Usaré algunos ejemplos para mostrar las diferencias / similitudes.

Comencemos con una configuración básica de tres granos de tipo A, B y C, con B y C siendo inyectado en 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>

Cargando 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 permite usarlas para simplificar el XML.

En primer lugar, permite autoaumentar el bbb y ccc propiedades en frijol A al igual que:

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 se simplifica 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 están auto conectadas?

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 la 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 adecuado:

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

Así que eliminemos las definiciones XML y reemplácelas por 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 frijoles, ni frijoles se autoconectan. ¡Nada!

Eso es porque, como dije en el primer párrafo, <context:annotation-config /> solo 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ó un bean y <context:annotation-config /> no tiene "objetivos" para trabajar.

Pero eso no será un problema para <context:component-scan> que puede escanear un paquete para que los "objetivos" trabajen. Cambiemos el contenido de la configuración XML en 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 a closelly en las clases, clase A tiene paquete com.yyy pero he especificado en el <context:component-scan> usar el paquete com.xxx así que esto extrañaba completamente mi A clase y solo recogido B y C que están en el com.xxx paquete.

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 tienes definiciones XML, tienes anotaciones.

Como último ejemplo, mantener las clases anotadas A, B y C y agregando lo siguiente al XML, ¿qué obtendremos después de cargar el contexto?

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

Todavía 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 frijol para la clase A no se obtiene escaneando, las herramientas de procesamiento todavía se aplican por <context:component-scan> en todos los frijoles registrados en el contexto de la aplicación, incluso para A que fue registrado manualmente en el XML.

Pero, ¿y si tenemos el siguiente XML, obtendremos frijoles 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 /> puede ser omitido si <context:component-scan> se especifica) pero Spring se encarga de ejecutarlos una sola 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" />

todavía generará 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 sobre lo explota.

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


1289
2017-09-17 17:16



Encontré esto agradable resumen de los cuales las anotaciones son recogidas por qué declaraciones. Al estudiarlo encontrarás 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 puedes ver <context:component-scan/> lógicamente se extiende  <context:annotation-config/> con escaneo de componentes CLASSPATH y características de Java @Configuration.


156
2017-09-14 10:39



Spring te permite hacer dos cosas:

  1. Autocableado de frijoles
  2. Autodescubrimiento de frijoles

1. Autocableado
Usualmente en applicationContext.xml usted define los frijoles y otros frijoles están conectados usando métodos constructor o setter. Puede transferir beans utilizando XML o anotaciones. En caso de que use anotaciones, debe activar las anotaciones y debe agregar <context:annotation-config /> en applicationContext.xml. Esto simplificará el estructura de la etiqueta de applicationContext.xml, porque no tendrá que conectar manualmente los beans (constructor o instalador). Puedes usar @Autowire la anotación y los beans estarán cableados por tipo.

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

2. Autodescubrimiento
Autodescubrimiento simplifica el XML un paso más allá, en el sentido de que ni siquiera necesita agregar el <bean> etiqueta adentro 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 de Spring. Las anotaciones son las siguientes: @Controlador, @Servicio, @Componente, @Repositorio. Mediante el uso <context:component-scan> y al señalar el paquete base, Spring detectará automáticamente y cableará los componentes en el contenedor Spring.


Como conclusión:

  • <context:annotation-config /> se usa para poder usar @Autowired anotación
  • <context:component-scan /> se usa para determinar la búsqueda de frijoles específicos e intento de autoenvío.

81
2017-08-12 02:29



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


29
2017-09-14 10:41



¡La diferencia entre los dos es realmente simple !.

<context:annotation-config /> 

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

Donde como

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

Habilita todo lo que <context:annotation-config /> puede hacer, además de usar estereotipos, por ejemplo .. @Component, @Service , @Repository. ¡Así que puede cablear frijoles enteros y no limitarse a constructores o propiedades!


27
2017-08-01 22:29



<context:annotation-config>: Escaneando y activando anotaciones para beans ya registrados en spring config xml.

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


@Autowired y @Required son objetivos nivel de propiedad Por lo tanto, bean debe registrarse en la primavera del COI antes de usar estas anotaciones. Para habilitar estas anotaciones, debe registrar los respectivos beans o incluir <context:annotation-config />. es decir <context:annotation-config /> trabaja solo con frijoles registrados.

@Necesario habilita RequiredAnnotationBeanPostProcessor  herramienta de procesamiento
@Autowired habilita AutowiredAnnotationBeanPostProcessor herramienta de procesamiento

Nota: Anotación en sí misma, no hay nada que hacer, necesitamos una Herramienta de procesamiento, que es una clase debajo, responsable del proceso central.


@Repository, @Service y @Controller son @Component, y ellos objetivos nivel de clase.

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


22
2018-01-02 02:22



los <context:annotation-config> la 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 @Autowired annotation.

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 pueden registrarse como definiciones de beans individuales, pero también pueden registrarse implícitamente al incluir <context:annotation-config> etiqueta en la configuración de primavera.

Tomado de la documentación de primavera de Configuración basada en anotaciones


Spring proporciona la capacidad de detectar automáticamente clases "estereotipadas" y registrar BeanDefinitions correspondientes con ApplicationContext.

De acuerdo con 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. Estos están diseñados para ser utilizados por herramientas y aspectos (lo que los convierte en un objetivo ideal para los puntos de corte).

Para autodetectar tales clases de 'estereotipos', <context:component-scan> etiqueta es requerida.

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


15
2017-08-31 09:08



<context:annotation-config>

Solamente resuelve las anotaciones @Autowired y @Qualifer, eso es todo, se trata de Inyección de dependencia, Hay otras anotaciones que hacen el mismo trabajo, creo que cómo @Inject, pero todo para resolver DI a través de anotaciones.

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

  • XML: <bean> 
  • @Anotaciones: @Component, @Service, @Repository, @Controller
  • JavaConfig: @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 cómo <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 frijoles, nada sobre <constructor-arg> y <property>, el DI se configura en sus propias clases a través de @Autowired. Significa que los Servicios usan @Autowired para sus componentes de Repositories y los Repositorios usan @Autowired para JdbcTemplate, DataSource etc..components.


9
2018-06-06 13:28