Se examinan más posibilidades que ofrece Spring a los desarrolladores para la gestión de beans, como la inicialización perezosa, o el descubrimiento automático de dependencias, entre otras.

Tipos de Beans

Por lo general se da por supuesto que todos los beans que instancia Spring implementan automáticamente el patrón Singleton. Sin embargo esto no es del todo cierto. Lo correcto es decir que ese es el funcionamiento por defecto, pero se pueden especificar otras formas de gestionar el ciclo de vida de los beans. De hecho, Spring permite incluso definir ciclos de vida personalizados por parte de las aplicaciones.

Spring soporta cinco tipos distintos de beans a través del atributo scope:

singleton: Valor por defecto. Una única instancia del bean.

prototype: Instancia tantos beans como se quiera con las características descritas. Es decir, no se crea un objeto al inicializar el contexto, sino cada vez que se requiere.

request: Instancia beans que tienen vigencia sólo durante el tiempo de vida de una petición HTTP. Válido sólo para aplicaciones web.

session: Instancia beans que tienen vigencia sólo durante el tiempo de vida de una sesión HTTP. Válido sólo para aplicaciones web.

globalSession: Instancia beans que tienen vigencia sólo durante el tiempo de una sesión global de un portlet. Válido sólo para aplicaciones web.

La opción por defecto no requiere mayor explicación. No obstante la opción prototype se puede entender mejor con el siguiente ejemplo, donde se definen dos beans que hacen referencia a otro que usa el valor prototype:

<bean id="zoo1" class="com.empresa.zoo.ZooServiceImpl">
  <property name="foodService" ref="mexicanFood"/>
</bean>

<bean id="zoo2" class="com.empresa.zoo.ZooServiceImpl">
  <property name="foodService" ref="mexicanFood"/>
</bean>
  
<bean id="mexicanFood" class="com.empresa.zoo.MexicanFoodServiceImpl"
      scope="prototype"/>

A diferencia de los ejemplos vistos hasta ahora, el bean mexicanFood no será un Singleton, y por lo tanto cada uno de los beans, zoo1 y zoo2, recibirá una instancia distinta de mexicanFood.

El resto de opciones para el atributo scope se verán cuando se traten los temas específicos relacionados con el desarrollo para la web.

Inicialización Perezosa

Por defecto, cuando Spring lee un fichero de configuración instancia automáticamente todos los beans de tipo Singleton definidos. Si se quiere evitar que algún bean sea instanciado automáticamente se puede utilizar el atributo lazy-init:

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl" lazy-init="true"/>

De esta forma el bean se instanciará la primera vez que sea usado, y no cuando arranque la aplicación. No obstante, si el bean «perezoso» forma parte de las dependencias de otro bean, Spring lo instanciará ignorando el atributo para asegurar que todo el sistema se inicializa correctamente.

Spring permite también cambiar la política de instanciación por defecto, permitiendo que ningún bean se instancie al arrancar si no se desea:

<beans default-lazy-init="true">
...
</beans>

Autowiring

Una forma de reducir el tamaño de los ficheros XML de configuración es utilizar la capacidad de autowiring de Spring. Esta característica permite a Spring detectar automáticamente las dependencias de un bean con otros, instanciando e inyectando por sí solo todos los objetos necesarios.

Spring soporta cuatro formas de autowiring a través del atributo autowire:

no: Opción por defecto, obliga a especificar las dependencias de forma manual utilizando ref.

byName: Fuerza a Spring a resolver dependencias por nombre. Es decir, si el bean tiene un setter llamado setAuditorio buscará un bean con nombre auditorio.

byType: Fuerza a Spring a resolver dependencias en base a los tipos de las propiedades del bean. Es decir, Spring examinará el tipo de las propiedades del bean y buscará algún bean que tenga el mismo tipo.

constructor: Fuerza a Spring a resolver dependencias en base a los tipos de los parámetros del constructor del bean.

Recuperemos por un momento el código del ejemplo original del zoológico con el servicio de comidas:

public class ZooServiceImpl implements ZooService{

    private FoodService foodService;

    public ZooServiceImpl(){
    }

    public void setFoodService(FoodService foodService){
        this.foodService = foodService;
    }
}

public class MexicanFoodServiceImpl implements FoodService{

    public MexicanFoodServiceImpl(){
    }
}

Y ahora consideremos la siguiente configuración, donde se definen dos beans sin aparente relación entre ellos, pero en la que se activa el autowiring por tipo en el bean zoo:

<bean id="zoo" class="com.empresa.zoo.ZooServiceImpl" autowire="byType"/>

<bean id="mexicanFood" class="com.empresa.zoo.MexicanFoodServiceImpl"/>

Cuando se instancie el bean zoo, Spring extraerá automáticamente sus propiedades, buscará otros beans que tengan el mismo tipo que cada una de ellas, y si los encuentra los inyectará como dependencias. En la práctica quiere decir que la propiedad foodService de zoo hará referencia al bean mexicanFood, ¡como por arte de magía!, ya que implementa la interface FoodService.

Si se quiere excluir un bean de toda la infraestructura de autowiring se puede utilizar el atributo autowire-candidate:

<bean id="mexicanFood" class="..." autowire-candidate="false"/>

Notar que esto no provocaría una excepción, sino que simplemente la propiedad foodService del bean zoo quedaría a nulo al no encontrar ningún candidato válido.

Más adelante se retomará el tema del autowiring, ya que esta no es la única forma de activarlo, ni probablemente la más recomendable.