Spring Définition bean statique
En théorie, une classe avec un contructeur privé par défaut ne peut pas être chargée. Sachant cela, il est possible de mettre en place des singleton ainsi.
package fr.ejn.tutorial.spring;
/**
* Class with private constructor to illustrate Spring can access private construtor.
*
* @author Etienne Jouvin
*
*/
public final class SingletonClass {
public static final SingletonClass INSTANCE = new SingletonClass();
/**
* @return static instance.
*/
public static SingletonClass getInstance() {
return INSTANCE;
}
/**
* Private constructor.
*/
private SingletonClass() {
}
}
Cependant, Spring est quand même capable d'instantier cette classe depuis le constructeur privé et cela peut entraîner une confusion lors de la mise en place de la configuration.
L'exemple utilise le mode de configuration par XML avec la version 3.2.10 de Spring, mais pourrait s'appliquer avec les annotations également. Le code source de l'article se trouve sur ici. L'illustration du chargement est disponible à partir du test unitaire MessageWrapperTest
.
Votre avis
Nobody voted on this yet
|
|
Définition bean
La première étape consiste à créer le bean avec un constructeur privé et une fonction getInstance
. Pour les besoins de l'example, une variable source
est mis en place pour tester les instances construites.
package fr.ejn.tutorial.spring;
/**
* Class with private constructor to illustrate Spring can access private construtor.
*
* @author Etienne Jouvin
*
*/
public final class SingletonClass {
public static final SingletonClass INSTANCE;
static {
INSTANCE = new SingletonClass();
INSTANCE.setSource("From static instance");
}
/**
* @return static instance.
*/
public static SingletonClass getInstance() {
return INSTANCE;
}
private String source;
/**
* Private constructor.
*/
private SingletonClass() {
this.source = "From private constructor";
}
/**
* @return the source
*/
public String getSource() {
return source;
}
/**
* @param source the source to set
*/
public void setSource(String source) {
this.source = source;
}
}
Ainsi, le contenu de la variable source
sera From static instance
pour le singleton Java, et From private constructor
quand l'instance sera intialisée depuis le constructeur privé.
Définition Spring
Le fichier applicationContext.xml
, chargé à l'initialisation de Spring, va permettre de définir une instance de MessageWrapper
avec injection d'une valeur dans la propriété message
.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-lazy-init="false">
<!-- Initialize logger, use log4j. -->
<bean id="log4jInitialization" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.springframework.util.Log4jConfigurer"/>
<property name="targetMethod" value="initLogging"/>
<property name="arguments">
<list>
<value>classpath:log4j.properties</value>
</list>
</property>
</bean>
<!-- Build instance. Spring can use the private constructor. -->
<bean name="privateInstance" class="fr.ejn.tutorial.spring.SingletonClass" />
<!-- Build instance using the static function getInstance, get the static instance. -->
<bean name="staticInstance" class="fr.ejn.tutorial.spring.SingletonClass" factory-method="getInstance" />
</beans>
Deux beans sont construits. Le premier utilise uniquement la définition de la classe, et permettra d'illustrer que cela passe par la constructeur privé. La deuxième définition utilise l'attribut factory-method
pour forcer l'utilisation de la fonction getInstance
, retournant le singleton Java.
Le test unitaire mis en place permet de valider que la première configuration ne retourne pas l'instance statique retournée par la fonction getInstance
.
Donc en conclusion, oui Spring est capable d'utiliser le constructeur privée (par introspection) alors que cela est théoriquement impossible en pur Java. Il serait impossible d'effectuer l'instruction new MessageWrapper()
.