¿Por que FactoryBean es útil?

3 minuto de lectura

En este post voy a tratar de explicar porque **FactoryBean** es increíblemente útil para alambrar (aplicar [DI](http://en.wikipedia.org/wiki/Dependency_injection)) aplicaciones hechas con [Spring Framework](http://www.springsource.org/).

La interfaz de FactoryBean dice lo siguiente:

public interface FactoryBean<T> {

	T getObject() throws Exception;

	Class getObjectType();

	boolean isSingleton();
}

La utilidad de la implementación de esta interfaz y su posterior declaración como Bean dentro del contexto de la aplicación, es que puede ser usada (como su nombre lo indica) como Factory para inyectar algún valor en alguna propiedad de otro Bean.

¿Dónde y cómo funciona? Dentro del ciclo de vida de la carga del Contexto de spring, la ejecución de la implementación de esta interfaz, esta justo antes de hacer los setters de las propiedades de un Bean. El funcionamiento es simple, siempre se ejecutará el método getObject() que retornará la instancia del tipo T.

Veamos una implementación simple y una configuración de contexto de spring:

public class RandomNumberFactoryBean implements FactoryBean<integer> {

	public Integer getObject() throws Exception {
		return Integer.valueOf(new Random().nextInt());
	}

	public Class getObjectType() {
		return Integer.class;
	}

	public boolean isSingleton() {
		return true;
	}

}

Esta simple implementación de FactoryBean retorna un Integer en el método getObject(), simplemente eso (obviamente en este método debes poner todo tu talento para resolver el valor que andas buscando, esto es un ejemplo simple).

El método getObjectType() es usado internamente por el framework para validar que el retorno de getObject() sea correcto o que este dentro de la jerarquía de clases, esto es en caso de que quieras restringir por tipo.

El último método isSingleton() es si quieres que esta clase (no importa la cantidad de declaraciones que tengas, siempre será la misma), es un tanto dificil de entender pero les sugiero que lean sobre el concepto de Singleton que tiene SpringFramework. En el ejemplo de configuración espero que les quede claro, de lo contrario, bienvenidas las preguntas.

Esta es la definición del Bean de ejemplo, en donde se hará uso del FactoryBean:

public class ExampleBean {

	private Integer _randomValue;

	public final Integer getRandomValue() {
		return _randomValue;
	}

	public final void setRandomValue(Integer randomValue) {
		_randomValue = randomValue;
	}

}

Aquí las configuraciones de contexto de spring.

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemalocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="exampleBean1" class="cl.pcollaog.factory.ExampleBean">
		<property name="randomValue">
			<bean class="cl.pcollaog.factory.RandomNumberFactoryBean" />
		</property>
	</bean>
       	
	<bean id="randomNumberFactoryBean" class="cl.pcollaog.factory.RandomNumberFactoryBean"/>

	<bean id="exampleBean21" class="cl.pcollaog.factory.ExampleBean">
		<property ref="randomNumberFactoryBean" name="randomValue"></property>
	</bean>

	<bean id="exampleBean22" class="cl.pcollaog.factory.ExampleBean">
		<property ref="randomNumberFactoryBean" name="randomValue"></property>
	</bean>

</beans>

Ejemplo 1:

Se declara el Bean exampleBean1 y que tiene como propiedad el atributo randomValue y cuyo valor será producto de la ejecución del Bean RandomNumberFactoryBean en el momento que el contexto de Spring es cargado. En este caso se utiliza la técnica de InnerBean, es decir, no se tiene una instancia del Bean para ser reutilizada sino que esta en la misma declaración del setter del atributo.

Ejemplo 2:

Este ejemplo hace lo mismo indicado arriba, sólo que no se aplica InnerBean sino que se extrae y es reutilizado en el bean exampleBean21 y exampleBean22. En este ejemplo entra en juego el método isSingleton(), si es true, quiere decir que el valor que entregará el FactoryBean siempre será el mismo para ambos Beans. Ahora bien, si se cambia a false, por cada setter, es decir, para exampleBean21 y exampleBean22 se realizara la ejecución de RandomNumberFactoryBean 2 veces. (En este caso, nos entregará dos valores aleatorios para cada bean)

En pocas palabras para cada Bean del ejemplo 2 habrá dos instancias de RandomNumberFactoryBean que entregará cada una un Integer para los atributos de los beans declarados.

Algo interesante de las implementaciones de FactoryBean es que luego de la carga del contexto, estas instancias son desechadas.

Espero les sea útil y cualquier pregunta sera bienvenida.

Comentar