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

Resuelto user938214097 asked hace 13 años • 0 respuestas

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

Por lo que he leído, parecen manejar diferentes anotaciones ( @Required, @Autowiredetc vs @Component,, etc), pero también por lo que he leído, registran el mismo postprocesador de beans@Repository .@Service clases

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

¿Alguien puede arrojar algo de luz sobre estas etiquetas? ¿En qué se parecen y en qué se diferencian, uno reemplaza al otro, se completan entre sí, necesito uno de ellos o ambos?

user938214097 avatar Sep 14 '11 17:09 user938214097
Aceptado

<context:annotation-config>se utiliza para activar anotaciones en beans ya registrados en el contexto de la aplicación (sin importar si fueron definidos 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 inyectados 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>

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

Bien, este es el resultado esperado. Pero esta es la primavera "al viejo estilo". Ahora tenemos anotaciones, así que usémoslas para simplificar el XML.

Primero, conectemos automáticamente las propiedades bbby cccdel bean Ade esta manera:

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

¡Bien, esto está mal! ¿Qué pasó? ¿Por qué mis propiedades no están cableadas automáticamente?

Bueno, las anotaciones son una característica interesante, pero por sí solas 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 él mismo.

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

Bien, esto es bueno, pero eliminé dos filas del XML y agregué una. Esa no es una gran diferencia. La idea con las anotaciones es que se supone que debe eliminar el XML.

Entonces, eliminemos las definiciones XML y reemplácelas 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 mantenemos esto:

<context:annotation-config />

Cargamos el contexto y el resultado es... Nada. No se crean beans ni se cablean automáticamente. ¡Nada!

Esto se debe a que, 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ó ningún bean y <context:annotation-config />no hay "objetivos" en los que trabajar.

Pero eso no será un problema para <context:component-scan>quienes puedan escanear un paquete en busca de "objetivos" en los que 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

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

Si observa detenidamente las clases, la clase Atiene un paquete com.yyy, pero lo he especificado en el <context:component-scan>paquete para usar com.xxx, por lo que se perdió por completo mi Aclase y solo recogió Blos 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 tienes definiciones XML, tienes anotaciones.

Como ejemplo final, manteniendo las clases anotadas Ay agregando lo siguiente al XML, ¿qué obtendremos después de cargar el contexto B?C

<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 de la clase Ano se obtiene mediante escaneo, las herramientas de procesamiento aún se aplican en <context:component-scan>todos los beans registrados en el contexto de la aplicación, incluso aquellos 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, sin 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 usted mismo registra las herramientas de procesamiento 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

Bien, eso es todo.

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

 avatar Sep 17 '2011 17:09

Encontré este buen resumen de qué anotaciones se recogen en 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 funciones Java @Configuration.

Tomasz Nurkiewicz avatar Sep 14 '2011 10:09 Tomasz Nurkiewicz

Spring te permite hacer dos cosas:

  1. Autocableado de frijoles
  2. Autodescubrimiento de frijoles

1. Cableado automático
Generalmente en applicationContext.xml usted define beans y otros beans se conectan mediante métodos constructores o setter. Puede conectar beans utilizando XML o anotaciones. En caso de que utilice anotaciones, debe activarlas y agregarlas <context:annotation-config />en applicationContext.xml . Esto simplificará la estructura de la etiqueta de applicationContext.xml , porque no tendrá que conectar manualmente beans (constructor o definidor). Puede utilizar @Autowireanotaciones y los beans se cablearán por tipo.

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

2. Detección automática
La detección automática simplifica el XML un paso más, en el sentido de que ni siquiera es necesario 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 descubrirá automáticamente y conectará los componentes al contenedor Spring.


Como conclusión:

  • <context:annotation-config />se utiliza para poder utilizar la anotación @Autowired
  • <context:component-scan />se utiliza para determinar la búsqueda de beans específicos y el intento de cableado automático.
user2673474 avatar Aug 12 '2013 02:08 user2673474

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

  • 3.9. Configuración de contenedor basada en anotaciones
  • 3.10. Escaneo de Classpath y componentes administrados
Sean Patrick Floyd avatar Sep 14 '2011 10:09 Sean Patrick Floyd