Spring Définition bean statique

De EjnTricks

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.


Hand-icon.png Votre avis

Nobody voted on this yet

 You need to enable JavaScript to vote


Java format icon.png 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é.


XML format icon.png 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().