<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
, B
y C
, con B
y C
siendo 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 bbb
y ccc
en bean A
así:
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 A
tiene un paquete, com.yyy
pero he especificado en el <context:component-scan>
paquete para usar, com.xxx
así que esto perdió por completo mi A
clase y solo recogió 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 tiene definiciones XML, tiene anotaciones.
Como ejemplo final, manteniendo las clases anotadas A
, B
y C
y 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 A
no 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 A
que 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.