‘manual 3.0’

1.4 Bean Scopes

Saturday, May 29th, 2010 Autor : gmateo

Cuando declaramos un bean ya sea usando archivos xml o anotaciones, sólo estamos definiendo una plantilla para la creación del bean, y no una instancia del bean. Recién cuando solicitemos una referencia al bean, Spring decidirá que instancia debe ser retornada, para esto se tiene en cuenta el valor "scope" del bean.

Los scopes soportados en son:

singleton :
Crea una sola instancia del bean por contenedor. Es el scope usado por defecto

prototype :
Crea una nueva instancia del bean cada vez que se pida una referencia al contenedor.

request :
Crea una nueva instancia por cada request HTTP. Sólo es válido en el contexto de aplicaciones Web. Simplificando las cosas podemos decir que se dan los siguientes pasos cada vez que el contenedor recibe un request:

a) El contenedor recibe el request
b) Se crean los objetos que tienen scope= WebApplicationContext.SCOPE_REQUEST ("request")
c) Cualquier llamada al contenedor para pedir una referencia al bean con scope="request", devuelve el bean creado en el punto b.
d) El contenedor termina de atender el request.
e) Los beans con scope="request" son eliminados.

session :
Crea una nueva instancia por cada session HTTP. Sólo es válido en el contexto de aplicaciones Web. Simplificando las cosas podemos decir que se dan los siguientes pasos:

a) Se crea la session Http.
b) Se crean los objetos que tienen scope= WebApplicationContext.SCOPE_SESSION ("session")
c) Cualquier llamada al contenedor para pedir una referencia al bean con scope="session", devuelve el bean creado en el punto b.
d) Se cierra la session Http.
e) Los beans con scope="session" son eliminados.

global-session :
Crea una nueva instancia por cada session HTTP global. Sólo es válido en el contexto de portlets.

Inyectar beans con scope distinto a singleton y prototype.

Imaginemos que nosotros queremos tener un objeto que sea creado cada vez que el contenedor recibe un request.

Entonces podríamos crear los siguiente

@Component
Controlador
@Autowired
RequestInfo requestInfo
@Component
RequestInfo

Con la configuración anterior tenemos el siguiente problema:

- El componente RequestInfo tiene scope="singleton", por tanto siempre será el mismo objeto.

Para tratar de arreglar eso hagamos el siguiente cambio:

@Component
@Scope(value = "request")
RequestInfo

Con esta configuración tenemos el siguiente problema:

- El componente Controlador tiene scope="singleton" entonces el contenedor al inicializarse creará una instancia de este bean y también seteará todas sus dependencias, en este caso seteará su atributo "requestInfo", y esta instancia de RequestInfo no será creada de nuevo con cada request.

Para arreglar esto hacemos lo siguiente:

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
RequestInfo

Con esta configuración, cuando el contenedor inicialice el bean "Controlador", seteará en la propiedad "requestInfo" un proxy al Componente RequestInfo. De esta manera cuando se requiera llamar a un método del RequestInfo, ese método será recibido por el proxy y este a su vez llamará al método en el objeto adecuado que es creado de acuerdo al valor del scope en este caso "request".

Algunos apuntes

Para setear el scope usar lo siguiente:

Usando archivos XML:

<bean class="Controlador" scope="prototype"/>
 
Usando anotaciones:
@Component
@Scope(value = "prototype")
public class Controlador {

Para setear el modo de proxy usar:

Usando archivos XML:

<bean class="RequestInfo" scope="request">
<aop:scoped-proxy proxy-target-class="true"/>
</bean>
 
proxy-target-class =”true” : es el valor por defecto, en este caso se crea un proxy de la clase usando CGLib. Acá se necesita tener el jar de cglib.
proxy-target-class =”false” :  en este caso se usa el soporte de proxy del JDK, no se necesita tener ningún jar adicional, pero si se necesita que la clase implemente una interface y el proxy es sobre los métodos de esa interface.
 
Usando anotaciones:
@Component
@Scope(value = "entrevista", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestInfo{
 
proxyMode = ScopedProxyMode.NO : no se crea ningún proxy es el valor por defecto.
proxyMode = ScopedProxyMode.TARGET_CLASS : se crea un proxy de la clase usando CGLib
proxyMode = ScopedProxyMode.INTERFACES : se crea un proxy usando el soporte del JDK, se necesita que la clase implemente una interface.

1.3.2 Autowiring usando anotaciones

Wednesday, May 26th, 2010 Autor : gmateo

Código Fuente: Ejemplo 8

A continuación vamos a ver cómo usando las anotaciones: @Autowired y @Resource podemos indicar al contenedor que atributos deben ser seteados y con qué beans.

Usando @Autowired

Al usar sólo esta anotación el contenedor hará un autowiring de tipo: “byType

   1: @Component

   2: public class Carro {

   3:     @Autowired

   4:     private Freno freno;

   5:     @Autowired

   6:     public Carro(Motor motor) {

   7:         this.motor = motor;

   8:     }

   9:     @Autowired

  10:     public void setVentana(Ventana ventana) {

  11:         this.ventana = ventana;

  12:     }

  13:     public Ventana getVentana() {

  14:         return ventana;

  15:     }

  16:     @Autowired

  17:     public void inicializarFaro(Faro faro) {

  18:         this.faro = faro;

  19:     }

  20: }

Clase: Carro

Línea 3-4 : El contenedor seteará en el atributo “freno” un bean del tipo “Freno”. Tener en cuenta que en este caso no es necesario:
a) Que el atributo sea público.
b) Que el atributo tenga getters ni setters.
Línea 5-8 : El contenedor usará este constructor para obtener la instancia de este bean “carro”. El contenedor enviará como parámetro un bean de tipo “Motor”
Línea 9-15 : El contenedor llamará a este método enviando como parámetro un bean de tipo “Ventana”. Notar que el método de la línea 10 es un setter.
Línea 16-19 : El contenedor llamará a este método enviando como parámetro un bean de tipo “Faro”. Notar que el método de la línea 17 podría ser cualquier método.
 
Se debe tener en cuenta que todas las partes marcadas con la anotación serán ejecutadas al inicializar el bean “carro”.

Usando @Autowired con @Qualifier

Al usar esta anotación el contenedor hará un autowiring de tipo: “byName

   1: @Component

   2: public class Carro {

   3:     @Autowired

   4:     @Qualifier("autoRadioConLectorDeCD")

   5:     private AutoRadio autoRadio;

   6:  

   7:     @Autowired

   8:     public void setCenicero(@Qualifier("ceniceroCromado") Cenicero cenicero) {

   9:         this.cenicero = cenicero;

  10:     }

  11: }

Clase: Carro
 
Línea 3-5 : El contenedor seteará  el atributo “autoRadio” con un bean que tenga el nombre “autoRadioConLectorDeCD”. La única clase que cumple con esto es:
@Component("autoRadioConLectorDeCD")
public class AutoRadio extends Accesorios {
 
Línea 7-10 : El contenedor llamará a este método enviando como parámetro un bean con el nombre: “ceniceroCromado”. La única clase que cumple con esto es:
@Component("ceniceroCromado")
public class Cenicero extends Accesorios {

Usando @Autowired utilitarios

   1: @Component

   2: public class Carro {

   3:     @Autowired

   4:     private Accesorios[] accesorios;

   5:     @Autowired

   6:     private List<Accesorios> accesoriosList;

   7:     @Autowired

   8:     private Map<String, Accesorios> accesoriosMap;

   9:     @Autowired

  10:     private MessageSource messageSource;

  11:     @Autowired

  12:     private ResourceLoader resourceLoader;

  13:     @Autowired

  14:     private ApplicationContext applicationContext;

  15: }

Clase: Carro
 
Línea 3-4: El contendor seteará en este arreglo todos los beans de tipo Accesorios. Seteará 2 beans uno de tipo: “Cenicero” y el otro de tipo “AutoRadio”.
@Component("autoRadioConLectorDeCD")
public class AutoRadio extends Accesorios {

@Component("ceniceroCromado")
public class Cenicero extends Accesorios {

Línea 5-6: El contendor seteará en esta Lista todos los beans de tipo Accesorios. Seteará 2 beans uno de tipo: “Cenicero” y el otro de tipo “AutoRadio”.

 
Línea 7-8 : El contendor colocará en el Map todos los beans de tipo Accesorio, como “key” colocará el nombre del bean. Si el Map estuviera definido así: Map<String, Object> el contenedor colocaría todos los beans, siempre usando el nombre del bean como key del Map.
 
Línea 9-14 : El contenedor seteará en estos atributos las referencias a los componentes de Spring: MessageSource, ResourceLoader, ApplicationContext.

Usando @Resource

Spring también soporta el uso de la anotación @Resource definida en: JSR 250: Common Annotations for the Java Platform.

Esta anotación sólo se puede usar en atributos y en métodos setter.

 

   1: @Component

   2: public class Motocicleta {

   3:     @Resource

   4:     private Freno freno;

   5:     @Resource(name = "llantaDeMoto")

   6:     private Llanta llanta;

   7:     @Resource

   8:     private MessageSource messageSource;

   9:     @Resource

  10:     private ResourceLoader resourceLoader;

  11:     @Resource

  12:     private ApplicationContext applicationContext;

  13:     @Resource

  14:     public void setMotor(Motor motor) {

  15:         this.motor = motor;

  16:     }

  17: }

Clase: Motocicleta
Línea 3-4 : El contenedor seteará en el atributo “freno” un bean del tipo “Freno”.
Línea 5-6 : El contenedor seteará en el atributo “llanta” un bean con el nombre “llantaDeMoto”. La única clase que cumple con esto es:
@Component("llantaDeMoto")
public class Llanta {
Línea 7-12 : El contenedor seteará en estos atributos las referencias a los componentes de Spring: MessageSource, ResourceLoader, ApplicationContext.

Línea 13-16 : El contenedor llamará a este método enviando como parámetro un bean de tipo “Motor”. Notar que el método de la línea 14 es un setter.

Usando @Inject

Spring también soporta la anotación @Inject que está definida en:JSR 330: Dependency Injection for Java. Para poder usar esto se necesita que el jar del JSR 330 esté incluido en el classpath.

1.3.1 Autowiring usando configuración XML

Wednesday, May 26th, 2010 Autor : gmateo

Código Fuente: Ejemplo 7

A continuación veremos los distintos tipos de autowiring usando beans definidos en un archivo XML.

   1: <bean id="ventana" class="com.aw.manual.ejemplo7.Ventana" />

   2: <bean id="frenoEspecial" class="com.aw.manual.ejemplo7.Freno" />

   3: <bean id="faro" class="com.aw.manual.ejemplo7.Faro" />

   4: <bean id="puerta" class="com.aw.manual.ejemplo7.Puerta" autowire-candidate="false"/>

   5: <bean id="carretilla" class="com.aw.manual.ejemplo7.Carretilla" autowire="no"/>

   6: <bean id="carro" class="com.aw.manual.ejemplo7.Carro" autowire="byName"/>

   7: <bean id="bicicleta" class="com.aw.manual.ejemplo7.Bicicleta" autowire="byType"/>

   8: <bean id="motocicleta" class="com.aw.manual.ejemplo7.Motocicleta" autowire="constructor"/>

Lista1: Archivo: app-config.xml

no : Tenemos el bean “carretilla” definido en la línea 5.

<bean id="carretilla" class="com.aw.manual.ejemplo7.Carretilla" autowire="no"/>
 
Tiene el atributo autowire="no", por tanto el contenedor no intentará setear ninguno de sus atributos.

byName : Tenemos el bean “carro” definido en la línea 6

<bean id="carro" class="com.aw.manual.ejemplo7.Carro" autowire="byName"/>

La clase tiene las siguientes propiedades:

public class Carro {
private Ventana ventana;
private Freno freno;
private Puerta puerta;
 
En este caso el contenedor analizará cada una de las propiedades y buscará algún bean que tenga el nombre de la propiedad. Por ejemplo tomará el atributo: “ventana”  y buscará en la Lista 1 un bean que tenga este id o name; vemos que el bean “ventana" cumple esta condición por tanto el contenedor seteará el atributo "ventana" con este bean.

Los valores de los atributos quedarán así:

"ventana": tendrá la referencia al bean "ventana"

"freno": seguirá en null ya que no existe ningún bean con ese id o name

"puerta": seguirá en null ya que si bien existe el bean con ese nombre  (Lista 1 – Línea 4) , este bean tiene autowire-candidate="false", lo cual indica al contenedor que no debe usar el ben “puerta” en el proceso de autowiring.

byType : Tenemos el bean “bicicleta” definido en la línea 7

<bean id="bicicleta" class="com.aw.manual.ejemplo7.Bicicleta" autowire="byType"/>

La clase tiene la siguiente propiedad:
public class Bicicleta {
private Freno freno;
 
En este caso el contenedor analizará cada una de las propiedades y buscará algún bean que tenga el mismo tipo. Por ejemplo tomará el atributo: “freno”  y buscará en la Lista 1 un bean que sea de tipo: “com.aw.manual.ejemplo7.Freno”; vemos que el bean “frenoEspecial" (Línea 2) cumple esta condición por tanto el contenedor seteará el atributo "freno" con este bean.

Los valores de los atributos quedarán así:

"freno": tendrá la referencia al bean "frenoEspecial"

constructor : Tenemos el bean “motocicleta” definido en la línea 8

<bean id="motocicleta" class="com.aw.manual.ejemplo7.Motocicleta" autowire="constructor"/>

La clase tiene los siguientes constructores :
public class Motocicleta {
public Motocicleta() {
}
public Motocicleta(Freno freno) {
this.freno = freno;
}
public Motocicleta(Freno freno, Faro faro) {
this.freno = freno;
this.faro = faro;
}
 
En este caso el contenedor analizará cada una de los constructores y buscará algún bean que tenga el mismo tipo que los parámetros del constructor. Por ejemplo tomará el primer constructor que tiene un solo parámetro “Freno”, buscará en la Lista 1 un bean que tenga este tipo, vemos que el bean “frenoEspecial" (Línea 2) cumple esta condición, si ya no existirían más constructores el contenedor usaría este constructor para instanciar el bean. Pero como hay más constructores con parámetros el contenedor seguirá buscando si existe algún otro constructor con mayor número de parámetros para los cuales pueda encontrar los beans adecuados.
 
El contenedor al final usará el constructor:
public Motocicleta(Freno freno, Faro faro) {

ya que es el que más parámetros tiene, y para los cuales existen beans que pueden ser seteados. En este caso el contedor llamará este constructor usando los beans: “frenoEspecial" (Línea 2) y “faro” (Línea 3)

1.3 Autowiring

Tuesday, May 25th, 2010 Autor : gmateo

Es el soporte de Spring que nos permite setear las dependencias de un bean de manera automática.

Los tipos de autowiring soportados por Spring son:

no : Ningún autowiring es ejecutado. Todas las dependencias deben indicarse explícitamente.

byName : El contenedor buscará un bean cuyo nombre o ID sea igual al nombre de una de las propiedades del bean. Si lo encuentra seteará la propiedad con la referencia al bean.

byType : El contenedor buscará un bean cuyo tipo sea igual al tipo de una de las propiedades del bean. Si lo encuentra seteará la propiedad con la referencia al bean. Si encuentra más de un bean lanzará la excepción UnsatisfiedDependencyException.

constructor : El contenedor evaluará todos los constructores definidos en el bean. Por cada uno de ellos encontrará los beans que sean compatibles en tipo con sus argumentos. El contenedor escogerá el constructor con mayor número de argumentos para los que haya encontrado beans compatibles. En caso de ambigüedad lanzará la excepción UnsatisfiedDependencyException.

Apuntes

a) Los tipos de autowiring son definidos por bean, y el valor por defecto es “no”.

b) Antes de la versión 3 existía el tipo "autodetect" pero ahora está "deprecated"

1.2.4 Beans – Inyectando otros beans

Monday, May 24th, 2010 Autor : gmateo

Código Fuente: ver Ejemplo 6

A continuación veremos las distintas opciones que tenemos para setear beans a otros beans.

Usando ref

A continuación veremos 3 maneras de setear el valor de un atributo con una referencia a otro bean

   1: <property name="timon" ref="timon"/>

   2: <property name="motor">

   3:     <ref bean="motor"/>

   4: </property>

   5: <property name="freno">

   6:     <ref local="freno"/>

   7: </property>

Archivo: app-config.xml

Línea 1 : Se setea el atributo “timon” con el bean “timon” que es un objeto de la clase Timon.

Líneas 2-4 : Se setea el atributo “motor” con el bean “motor”

Líneas 5-7 : Se setea el atributo “freno” con el bean “freno”

Observando la línea 3 y la línea 6, vemos que en una de ellas se usa “bean” y en la otra se usa “local”. La diferencia radica en que cuando se usa ”local” se va a buscar que el bean esté definido en el mismo archivo, y sino es así el parseador de XML lanzará una excepción.

Usando Inner Beans

   1: <bean id="carro" class="com.aw.manual.ejemplo6.Carro"

   2:       p:ventanaIzquierda-ref="ventanaIzquierda" >

   3:     <property name="ventanaDerecha">

   4:         <bean class="com.aw.manual.ejemplo6.Ventana"/>            

   5:     </property>

Archivo: app-config.xml

Línea 3-5 : Se setea el atributo “ventanaDerecha” con un bean anónimo de tipo “Ventana”

Línea 4 : Se define un “inner bean” que no puede ser referenciado en otro lugar, ni puede ser accedido directamente usando el ApplicationContext. 

Usando p-namespace

   1: <bean id="carro" class="com.aw.manual.ejemplo6.Carro"

   2:       p:ventanaIzquierda-ref="ventanaIzquierda" >

Archivo: app-config.xml

Línea 2 : Se está usando el prefijo “p” para poder acceder a un atributo del bean “carro”, en este caso se trata del atributo: “ventanaIzquierda” al cual se le setea una referencia a otro bean.

Se debe notar que cuando se usa el prefijo “p”  para setear referencias a otro bean se debe agregar “-ref” al final del nombre del atributo, sino se hace esto Spring asumirá que estamos asignando un String a ese atributo y esto originará un error de tipo.

Apuntes acerca el elemento idref

Esta parte se incluye para aclarar que el elemento “idref”, NO SE USA para setear las referencias a otro bean, sino más bien se usa para setear los nombres de otros beans pero de una manera segura. Se dice de una manera segura ya que el contenedor valida que exista un bean con ese nombre.

   1: <property name="nombreDelBeanMotor">

   2:     <idref local="motor"/>

   3: </property>

   4: <property name="nombreDelBeanTimon">

   5:     <idref bean="timon"/>

   6: </property>

   7: <property name="nombreDelBeanFreno" value="freno"/>

Archivo: app-config.xml

Línea 1-3 : Setea el atributo “nombreDelBeanMotor” con el valor String “motor”

Línea 4-6 : Setea el atributo “nombreDelBeanTimon” con el valor String “timon”

Línea 7 : Setea el atributo “nombreDelBeanFreno” con el valor String “freno”

Los 3 seteos son casi iguales, ya que en todos lo que se hace es setear un valor de tipo String a una propiedad del bean. Las diferencias son las siguientes:

a) Entre el primero y el segundo (“nombreDelBeanMotor” / “nombreDelBeanTimon”) es que en el primero por el uso de “local” el parseador va a asegurarse que la definición “motor”  esté en el mismo archivo.

b) Entre los dos primeros (“nombreDelBeanMotor” / “nombreDelBeanTimon”) y el tercero (“nombreDelBeanFreno”) es que en los 2 primeros el contendor valida que existan beans con esos nombres, en cambio en el tercero el contenedor no valida nada.

1.2.3 Beans – Inyectando valores simples

Monday, May 24th, 2010 Autor : gmateo

Código Fuente: ver Ejemplo 5

A continuación se va a mostrar cómo se inyectan valores simples a un bean.

Inyectando String, int, double, etc

   1: <bean id="persona1" class="com.aw.manual.ejemplo5.Persona">

   2:     <property name="nombre" value="José"/>

   3:     <property name="apellidos" value="Mesías Torres"/>

   4:     <property name="edad" value="20"/>

   5:     <property name="totalDeEfectivo" value="100.5"/>

Archivo: app-config.xml

Línea 2,3 : Se setean valores tipo String

Línea 4 : Se setea un valor tipo int

Línea 5 : Se setea un valor tipo double

Inyectando Arreglos y Colecciones

Spring soporta el seteo de atributos de tipo arreglo y de las colecciones: List, Set, Map y Properties

Arrays:

<property name="ahorrosComoArray">
<list>
<value>10</value>
<value>40</value>
</list>
</property>

Archivo: app-config.xml

El atributo “ahorrosComoArray” es de tipo “String[]”

Collection

<property name="ahorrosComoCollection">
<list>
<value>11</value>
<value>41</value>
</list>
</property>

Archivo: app-config.xml

El atributo “ahorrosComoCollection” es de tipo “Collection”

List

<property name="ahorros">
<list>
<value>20</value>
<value>30</value>
</list>
</property>

Archivo: app-config.xml

El atributo “ahorros” es de tipo “List”

Set

<property name="telefonos">
<set>
<value>1234323</value>
<value>2234323</value>
</set>
</property>

Archivo: app-config.xml

El atributo “telefonos” es de tipo “Set”

Map

<property name="cuentasYPasswords">
<map>
<entry key="Twitter" value="1234"/>
<entry key="Facebook" value="2345"/>
</map>
</property>

Archivo: app-config.xml

El atributo “cuentasYPasswords” es de tipo “Map”

Properties

<property name="apuntes">
<props>
<prop key="HoraIngreso">8:30</prop>
<prop key="Refrigerio">12:30</prop>
<prop key="Salida">10:30</prop>
</props>
</property>
<property name="otrosApuntes">
<value>
HoraIngreso = 8:30
Refrigerio =12:30
Salida =10:30
</value>
</property>

Archivo: app-config.xml

Acá se muestran 2 maneras de setear atributos de tipo Properties, ambos atributos “apuntes” y “otrosApuntes” son de este tipo

Inyectando valores Nulos

<property name="valorNulo">
<null/>
</property>
Archivo: app-config.xml

Usando un constructor con argumentos para crear un bean

<bean id="persona2" class="com.aw.manual.ejemplo5.Persona">
<constructor-arg value="José"/>
<constructor-arg value="Mesías Torres"/>
<property name="edad" value="20"/>
</bean>
Archivo: app-config.xml

Para crear el bean “persona2” se usará el constructor con 2 parámetros.

Usando p-namespace

Al setear los valores de un bean nos permite usar directamente los atributos del bean en lugar de usar las entradas <property/>.

   1: <beans xmlns="http://www.springframework.org/schema/beans"

   2:        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   3:        xmlns:p="http://www.springframework.org/schema/p"

   4:        ...>

   5:     ...    

   6:     <bean id="persona3" class="com.aw.manual.ejemplo5.Persona"

   7:           p:nombre="Roberto"

   8:           p:apellidos="Franco Arco"/>

   9: </beans>

Archivo: app-config.xml

Línea 3 : Se define el namespace prefix “p”

Línea 7,8 : Usando el prefijo “p” se hace referencia directa a los atributos del bean “persona3”

1.2.2 Beans – Agregando un bean al contenedor de Spring

Thursday, May 20th, 2010 Autor : gmateo

Código Fuente: ver Ejemplo 4

Se puede agregar un bean al contenedor de Spring de las siguientes maneras:

Declarando la clase en un xml

Sólo es necesario colocar una entrada como la siguiente, en cualquiera de los archivos que serán usados para levantar el contenedor.

<bean class="com.aw.manual.ejemplo4.Carro"/>

Declarando el método que creará el bean

En este método se indica que método debe ser llamado cuando se quiera una instancia de un bean. Este método puede ser un método estático o un método de instancia.

Usando un método de Instancia

   1: <bean id="proveedorDeVentanas" class="com.aw.manual.ejemplo4.ProveedorDePiezas"/>

   2: <bean id="ventana"

   3:       factory-bean="proveedorDeVentanas"

   4:       factory-method="obtenerVentana"/>

Archivo: app-config.xml
Las líneas importantes son:
Linea 1: Se define el bean que tiene el método que será encargado de proveer la instancia del bean “ventana”
Linea 2: Se define el bean “ventana”. Este bean es el objeto devuelto por el método “obtenerVentana” del bean “proveedorDeVentanas”.

Usando un método estático

<bean id="puerta"
class="com.aw.manual.ejemplo4.ProveedorDePiezas"
factory-method="obtenerPuerta"/>
Archivo: app-config.xml
Acá se define el bean “puerta”. Este bean es el objeto devuelto por el método estático “obtenerPuerta” de la clase “ProveedorDePiezas”

Usando la anotación de Component o algún derivado

Para que esto funcione se necesita:

1) Definir el o los paquetes base dentro de los cuales se buscarán las clases que tengan la anotación @Component o algún derivado.

<context:component-scan base-package="com.aw.manual.ejemplo4"/>
Archivo: app-config.xml
 
2) Colocar la anotación @Component o algún derivado a la clase.
 
@Component
public class Timon {
Clase: com.aw.manual.ejemplo4.Timon

Usando la anotación de @Bean

Para que funcione se necesita lo siguiente:

1) Definir el o los paquetes base dentro de los cuales se buscarán las clases que tengan la anotación @Component o algún derivado.

<context:component-scan base-package="com.aw.manual.ejemplo4"/>
Archivo: app-config.xml
 
2) Colocar la anotación @Bean en los métodos de clases que tengan la anotación de @Configuration, @Component o una derivada de @Component.
 
2.1) Clase con anotación de @Configuration
@Configuration
public class ProveedorDeFaro {
@Bean
public Faro obtenerFaro() {
return new Faro();
}
}

2.2) Clase con anotación de @Component
@Component
public class ProveedorDeMotor {
@Bean
public Motor obtenerMotor() {
return new Motor();
}
}
 
2.3) Clase con una anotación derivada de @Component
@ComponenteEspecifico
public class ProveedorDeVentana {

@Bean
public Ventana obtenerVentana(){
return new Ventana();
}
}
Donde la anotación @ComponenteEspecifico está definido de la siguiente manera:
@java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Documented
@org.springframework.stereotype.Component
public @interface ComponenteEspecifico {
java.lang.String value() default "";
}

Agregando el objeto al contexto de Spring registeSingleton

   1: String configFiles = "com/aw/manual/ejemplo4/app-config.xml";

   2: GenericApplicationContext appCtx = new GenericApplicationContext();

   3: appCtx.getBeanFactory().registerSingleton("freno", new Freno());

   4: new XmlBeanDefinitionReader(appCtx).loadBeanDefinitions(new ClassPathResource(configFiles));

   5: appCtx.refresh();

   6: Carro carro = appCtx.getBean(Carro.class);

Clase:  com.aw.manual.ejemplo4.EjemploInicializacion

Las líneas importantes son:

Línea 3: Acá se registra el bean “freno”

Línea 5: Acá se refresca el contexto, para que también se incluya el bean agregado en la línea 3.

1.2.1 Bean – Acerca de los nombres

Thursday, May 6th, 2010 Autor : gmateo

Un Bean puede tener uno o más identificadores, éstos deben ser únicos dentro del contenedor que maneja el bean.

Normalmente el bean tiene un sólo identificador pero si se requiere más de uno, los demás serán considerados alias.

En la configuración usando XML, se usa los atributos id y name para especificar la identificación del bean. El id es un atributo XML, por lo cual el parser XML puede hacer una validación extra asegurando que sea único. En el atributo "name" se puede poner más de un nombre ya sea separado por comas, punto y comas o espacios en blanco, todos estos nombres serán alias del bean.

No es obligatorio setear el atributo id o name, si ninguno ha sido seteado Spring generará un nombre único para ese bean.

Ahora veamos un ejemplo:

Código Fuente: ver Ejemplo3

   1: <?xml version="1.0" encoding="UTF-8"?>

   2: <beans xmlns="http://www.springframework.org/schema/beans"

   3:        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"

   4:        xmlns:context="http://www.springframework.org/schema/context"

   5:        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

   6:                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd

   7:                 http://www.springframework.org/schema/oxm http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

   8:     <context:component-scan base-package="com.aw.manual.ejemplo3"/>

   9:     <bean id="auto" name="primerAliasDelBeanAuto,segundoAliasDelBeanAuto;tercerAliasDelBeanAuto cuartoAliasDelBeanAuto" class="com.aw.manual.ejemplo3.Carro"/>

  10:     <alias name="tercerAliasDelBeanAuto" alias="aliasDeUnAlias"/>

  11:     <bean class="com.aw.manual.ejemplo3.Carro" />

  12:     <alias name="com.aw.manual.ejemplo3.Carro" alias="aliasDelBeanDeTipoCarroQueNoTieneIdNiName"/>

  13: </beans>

Archivo: app-config.xml

Las líneas importantes son:

Línea 9: Se define un bean de la clase Carro, que tiene como id auto y varios alias definidos en el valor del atributo name.

Línea 10: Se define un alias de un alias para el bean de la línea 9.

Teniendo en cuenta estas dos líneas, podremos tener la referencia a este bean de las siguientes maneras:

(Carro)appCtx.getBean("auto");
(Carro)appCtx.getBean("primerAliasDelBeanAuto");
(Carro)appCtx.getBean("segundoAliasDelBeanAuto");
(Carro)appCtx.getBean("tercerAliasDelBeanAuto");
(Carro)appCtx.getBean("cuartoAliasDelBeanAuto");
(Carro)appCtx.getBean("aliasDeUnAlias");

Línea 11: Se define un bean sin indicar explícitamente ni el id ni el name, en este caso Spring asignará un nombre.

Línea 12: Se define un alias para el bean de la línea 11

Teniendo en cuenta estas dos líneas, podremos tener la referencia a este bean de las siguiente manera:

 
(Carro) appCtx.getBean("aliasDelBeanDeTipoCarroQueNoTieneIdNiName");

Mostrando todos los nombres de los beans del ejemplo3

Para mostrar los nombres de los beans manejados por Spring que están incluidos en el Ejemplo3 ejecutamos el main de la clase: EjemploInicializacion,

 

public class EjemploInicializacion {
public static void main(String[] args) {
String configFiles = "classpath*:**/ejemplo3/app-config.xml";
ApplicationContext appCtx = new ClassPathXmlApplicationContext(configFiles);
String[] beanNames = appCtx.getBeanDefinitionNames();
for (int i = 0; i < beanNames.length; i++) {
String beanName = beanNames[i];
System.out.println(beanName);
}
}
}

lo cual nos da como resultado lo siguiente:

   1: puertaPrincipal

   2: timon

   3: org.springframework.context.annotation.internalConfigurationAnnotationProcessor

   4: org.springframework.context.annotation.internalAutowiredAnnotationProcessor

   5: org.springframework.context.annotation.internalRequiredAnnotationProcessor

   6: org.springframework.context.annotation.internalCommonAnnotationProcessor

   7: auto

   8: com.aw.manual.ejemplo3.Carro#0

Línea 1: puertaPrincipal, es el nombre con el cual está declarado el bean de la clase Puerta que está definido de la siguiente manera:

@Component("puertaPrincipal")
public class Puerta {

Línea 2: timon, es el nombre con el cual está declarado el bean de la clase Timon que está definido de la siguiente manera:

@Component
public class Timon {

Líneas 3-6: Son beans que Spring coloca.

Línea 7: auto, es el nombre del bean que definimos en el xml, en este caso colocamos explícitamente el id y el name para este bean.

Línea 8: com.aw.manual.ejemplo3.Carro#0, es el nombre que Spring genera para el bean que declaramos en el xml sin indicar ni id ni name.

1.2 Bean

Thursday, May 6th, 2010 Autor : gmateo

Se llama "Bean" a todo objeto manejado por el contenedor IoC de Spring. Éstos son creados ya sea con los archivos de configuración XML o con las anotaciones que se colocan en las clases.

1.1 Maneras de configurar el contenedor de Spring

Saturday, April 24th, 2010 Autor : gmateo

Antes sólo se podía inicializar el contenedor de Spring usando archivos xml, ahora con la versión 3 es posible inicializar el contenedor usando archivos xml o usando sólo clases java. A continuación se describen estos modos de inicialización.

a) Usando archivos XML

Código Fuente: ver Ejemplo1

En este caso se debe crear 1 o más archivos xml donde se definirán los beans a ser manejados por spring.

Usaremos el siguiente archivo:

   1: <?xml version="1.0" encoding="UTF-8"?>

   2: <beans xmlns="http://www.springframework.org/schema/beans"
   3:        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
   4:        xmlns:context="http://www.springframework.org/schema/context"

   5:        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   6:                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
   7:                 http://www.springframework.org/schema/oxm http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

   8:     <context:component-scan base-package="com.aw.manual.ejemplo1"/>

   9:     <bean class="com.aw.manual.ejemplo1.Carro"/>

  10: </beans>

Archivo: app-config.xml

Las líneas importantes son:

Línea 8: Se define el paquete desde donde se buscará las clases que tengan alguna anotación de tipo Component o derivado. Todas estas clases serán manejadas por el contenedor.

Linea 9: Se define un bean de tipo "Carro"

Para inicializar el contenedor usaremos la siguiente clase:

   1: package com.aw.manual.ejemplo1;

 

   2: ...

 

   3: public class EjemploInicializacion {

   4:     public static void main(String[] args) {

   5:         String configFiles = "classpath*:**/app-config.xml";

   6:         ApplicationContext appCtx = new ClassPathXmlApplicationContext(configFiles);

   7:         Carro carro = appCtx.getBean(Carro.class);

   8:         System.out.println("Carro:<"+carro+">");

   9:         Timon timon = appCtx.getBean(Timon.class);

  10:         System.out.println("Timon:<"+timon+">");

  11:         ProveedorDePiezas proveedorDePiezas = appCtx.getBean(ProveedorDePiezas.class);

  12:         System.out.println("ProveedorDePiezas:<"+proveedorDePiezas+">");

  13:         Puerta puerta = appCtx.getBean(Puerta.class);

  14:         System.out.println("Puerta:<"+puerta+">");

  15:     }

 

  16: }

Las líneas importantes son:

Línea 5: Se indica la ubicación del archivo xml. En este caso estamos usando el classpath para indicar la ubicación.

Línea 6:  Acá se inicializa el contenedor de Spring.

Línea 7: Se obtiene una instancia de la clase Carro.

Algunas cosas a tener en cuenta:

- Para que la clase Timon sea manejada por Spring se tuvo que poner la anotación @Component en la definición de la clase. Y como esta clase está en el paquete: com.aw.manual.ejemplo1, Spring se encargará de manejarla.

- Lo mismo pasa con la clase ProveedorDePiezas, claro que hay q tener en cuenta que en este caso se usó la anotación: @Configuration, que sirve para definir objetos especiales, que pueden proveer beans.

- La clase Puerta es creado por uno de los métodos de la clase ProveedorDePiezas.

   1: package com.aw.manual.ejemplo1;

   2: @Configuration

   3: public class ProveedorDePiezas {

   4:     @Bean

   5:     public Puerta obtenerPuerta() {

   6:         return new Puerta();

   7:     }

   8: }

b) Usando clases java

Código Fuente: ver Ejemplo2

No es necesario crear ningún archivo xml, todo se hace usando clases java.

Para inicializar el contenedor usaremos la siguiente clase:

   1: package com.aw.manual.ejemplo2;

   2: ...

   3: public class EjemploInicializacion {

   4:     public static void main(String[] args) {

   5:         AnnotationConfigApplicationContext appCtx = new AnnotationConfigApplicationContext(Carro.class);

   6:         appCtx.scan("com.aw.manual.ejemplo2");

   7:         appCtx.refresh();

   8:         Carro carro = appCtx.getBean(Carro.class);

   9:         System.out.println("Carro:<"+carro+">");

  10:         Timon timon = appCtx.getBean(Timon.class);

  11:         System.out.println("Timon:<"+timon+">");

  12:         ProveedorDePiezas proveedorDePiezas = appCtx.getBean(ProveedorDePiezas.class);

  13:         System.out.println("ProveedorDePiezas:<"+proveedorDePiezas+">");

  14:         Puerta puerta = appCtx.getBean(Puerta.class);

  15:         System.out.println("Puerta:<"+puerta+">");

  16:     }

  17: }

Las líneas importantes son:

Línea 5: Se inicializa el contendor de Spring y se indica explícitamente que el contenedor se encargará de manejar la clase Carro. Tener en cuenta que la clase AnnotationConfigApplicationContext es la que nos permite obviar los xml.

Línea 6: Se setea el paquete desde el cual Spring buscará las clases que tengan la anotación de Component o algún derivado, para incluirlos dentro del contenedor.

Línea 7: Se llama a refrescar el contenedor, el cual ya fue inicializado en la Línea 5. De esta manera Spring podrá localizar las clases que necesitan ser manejadas por el contenedor.

Notas

Para los ejemplos se han usado las anotaciones: @Component, @Configuration, @Bean, el detalle de las mismas se verá en otras entradas.