Integrar Singletons En Spring
¿Cómo declarar un objeto en Spring Framework que no tiene constructor público, y cuyas instancias se deben obtener a través de un método (como ser, una clase Singleton)?.
La situación
Supongamos la siguiente clase Singleton (hey, existe un único Imperio Irken, todos de pie!):
public class ImperioIrken { private static ImperioIrken instance = new ImperioIrken();
private ImperioIrken() { }
public static ImperioIrken getInstance() { return instance; }
//insertar métodos para controlar la población aquí... }
El problema
La clase ImperioIrken no tiene un constructor público. ¿Cómo podemos hacer para declararla en Spring, y así poder inyectarla a otros beans?
Obviamente, la primer solución sería no crear esta clase como Singleton (un patrón en desuso, dicho sea de paso). Sin embargo, esto no siempre es posible... ¿qué pasaría si la clase ImperioIrken no fuera nuestra, sino de un framework externo?
Con lo cual, vamos a tener que lidiar con este singleton de alguna manera.
La solución: la interfaz FactoryBean
Spring provee la interfaz org.springframework.beans.factory.FactoryBean. Los objetos que cumplan esta interfaz serán usados por spring como factory de otros objetos.
La interfaz tiene 3 métodos a implementar, de los cuales el método getObject() es el que deberá devolver la instancia de nuestro objeto en cuestión.
Luego, en el archivo de configuración, se declara el factory de nuestro bean en vez de la clase original.
Así, un factory para nuestro ImperioIrken quedaría:
public class ImperioIrkenFactoryBean implements FactoryBean {
public Object getObject() { return ImperioIrken.getInstance(); }
public Class getObjectType() { return ImperioIrken.class; }
public boolean isSingleton() { return true; } }
Finalmente, en nuestro archivo de configuración declararemos a ImperioIrkenFactoryBean en lugar del bean original. Spring, al detectar que implementa la interfaz FactoryBean, invocará al método getObject() para obtener la instancia.
<beans> <bean id="imperioIrken" class="ejemplo.ImperioIrkenFactoryBean" /> </beans>
Al pedirle a Spring que nos de una instancia de "imperioIrken" nos devolverá justamente una instancia de la clase ImperioIrken, creada a través del método getObject() de ImperioIrkenFactory.