[Spring] Gestion des propriétés et des messages

Dans ce billet je vais faire un rapide aperçu d'une des manières de gérer les messages et les propriétés d'un projet avec Spring.

Généralement, les messages sont stockés dans des fichiers properties inclus dans le projet.

Il y a deux manières de déclarer les fichiers properties, selon les besoins d'utilisation des propriétés.

Placeholder

Il arrive souvent que des propriétés techniques aient besoin d'être injectées dans des beans par Spring.

<bean id="testBean" class="com.netapsys.Bean">
     <property name="adress" value="${server.adress}" />
</bean>

Dans cet exemple, la propriété server.adress est stockée dans un fichier properties, et sera injectée par Spring au démarrage du serveur.

La liste des fichiers dans lesquels Spring ira rechercher ces propriétés est à définir dans un bean de type PropertyPlaceholderConfigurer :

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
     <property name="locations">
          <list>
               <value>classpath:/config/project.properties</value>
               <value>classpath:/config/ldap.properties</value>
               <value>file:/etc/netapsys/config.properties</value> <!-- Les propriétés peuvent être surchargées dans un fichier présent sur le système. -->
          </list>
     </property>
     <property name="ignoreResourceNotFound" value="true"/> <!-- Permet de ne pas avoir d'erreur si un fichier n'est pas présent. -->
</bean>

À noter qu'il est possible de définir plusieurs beans de type PropertyPlaceholderConfigurer, et de customiser la syntaxe du placeholder (qui est par défaut ${key}).

MessageSource

Pour récupérer des messages depuis le code (en récupérant le contexte Spring grâce à la classe ApplicationContext), ou pour les afficher dans les JSP grâce au tag spring:message, il faut définir un bean messageSource étendant la classe AbstractMessageSource.

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
     <property name="basenames"> <!-- Liste des fichiers à utiliser, présents dans le classpath. -->
          <list>
               <value>ErrorResources</value>
               <value>LabelResources</value>
               <value>config/project</value>
          </list>
     </property>
     <property name="alwaysUseMessageFormat" value="true" /> <!-- Formatage de tous les messages. -->
     <property name="useCodeAsDefaultMessage" value="true"/> <!-- Utilise le code en tant que valeur par défaut. -->
</bean>

Cette implémentation est la plus simple, et convient dans la majorité des cas. Cependant dans certains projets, le client peut vouloir changer certains messages ou propriétés sans avoir à redémarrer le serveur. Or, comme indiqué, la classe ResourceBundleMessageSource se base sur la classe ResourceBundle du JDK, qui ne permet pas le rechargement des messages à chaud.

Dans ce cas il faut se tourner vers une autre implémentation de Spring : ReloadableResourceBundleMessageSource. La déclaration sera quelque peu différente :

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
     <property name="basenames"> <!-- Liste des fichiers à utiliser, présents dans le classpath. -->
          <list>
               <value>file:/etc/netapsys/config</value> <!-- Les propriétés peuvent être surchargées dans un fichier présent sur le système (premier élément de la liste !).  -->
               <value>classpath:ErrorResources</value>
               <value>classpath:LabelResources</value>
               <value>classpath:config/project</value>
          </list>
     </property>
     <property name="alwaysUseMessageFormat" value="true" /> <!-- Formatage de tous les messages. -->
     <property name="useCodeAsDefaultMessage" value="true"/> <!-- Utilise le code en tant que valeur par défaut. -->
     <property name="cacheSeconds" value="10" /> <!-- Taux de rafraîchissement des messages mis en cache. -->
</bean>

Contrairement à la première implémentation, il est maintenant possible d'indiquer un fichier présent sur le système, dans lequel notre client ira surcharger les messages voulus par exemple.
Petite explication de la propriété cacheSeconds : lors de l'affichage d'un message, il est mis dans un cache. Si la clé du message est redemandée après "cacheSeconds" secondes, le bundle ira revérifié dans les fichiers properties si sa valeur n'a pas changée.

De plus, cette implémentation peut aussi être intéressante à utiliser dans le cadre du développement, lors de la construction des IHM.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.