avril
2010
Problème
Sur certains projets, j’ai eu l’occasion de voir des fichiers de configuration Spring de ce type :
<import resource="monitoring-environnement2.xml"/>
<import resource="monitoring-environnement3.xml"/>
Et bien évidemment, chacun des fichiers de configurations importés était tous semblables, avec comme seule différence les noms de beans Spring ou des valeurs de propriétés.
Si demain, un nouvel environnement devait être ajouté, je vous le donne dans le mille : un copier / coller, un s/environnement1/nouvel-environnement/g !
Même si cela fonctionne bien, ce n’est pas la solution la plus propre : Si le système de monitoring devait être modifié, il faudrait éditer X fichiers, avec le risque d’oublier un fichier, ou un valeur…
Solution 1 : Créer un namepace dédié au monitoring
Une première solution possible serait de remplacer ces imports par un namespace dédié au monitoring. Il suffirait dès lors d’utiliser une configuration de ce type :
<monitoring:environnement name="environnement2"/>
C’est déjà beaucoup plus propre, mais cette solution n’est pas des plus pratiques :
La configuration « générique » sera réalisée via une API spécifique à Spring, que peu de développeurs connaissent ( BeanDefinitionParser, ParserContext, BeanDefinitionRegistry, ..), ce qui rends toute modification assez complexe
Le namespace sera dédié au monitoring ! Si le domaine des fichiers était tout autre, il faudrait développer un nouveau namespace.
Le namespace va cacher aux utilisateurs les beans réellement instanciés.
Bref, c’est déjà mieux mais pas encore suffisamment claire et simple.
Solution 2 : Créer un namepace d’importation de modèles de configuration
Afin de répondre à ces problématique, il est possible de créer un namespace beaucoup plus générique. Celui qui permettrait d’importer une configuration classique (un modèle), mais en remplaçant certaines variables par des valeurs.
Le modèle serait un fichier de configuration Spring tout à fait compréhensible par des habitués de Spring, mais dans laquelle des variables seraient définies :
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">
<bean name="scheduledTimeTask.${environnement}" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask" ref="monitoringTask.${environnement}"/>
<property name="delay" value="1000"/>
<property name="period" value="1000"/>
</bean>
<bean name="timer.${environnement}" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref bean="scheduledTimeTask.${environnement}"/>
</list>
</property>
</bean>
<bean name="monitoringTask.${environnement}" class="be.hikage.springtemplate.MonitoringTimerTask">
<property name="url" value="${${environnement}.url}"/>
</bean>
</beans>
Ici, ${environnement}, est une variable qui sera définie lors de l’importation du modèle :
<hikage:variable name="environnement" value="environnement1"/>
</hikage:import-template>
Conclusion
Cette solution possède donc plusieurs avantages :
En cas de modification du modèle, un seul fichier devra être modifié.
Le namespace pourra être utilisé pour différent domaine ( monotoring, etc .. )
Le modèle sera modifiable par n’importe quel développeur connaissant Spring, et tout à fait lisible
Informations
Ce projet est disponible sous licence Apache 2 sur http://code.google.com/p/spring-import-template/
Non on ne peut pas utiliser d’aliais car ce ne sont pas « uniquement » le nom qui change.
Des valeurs peuvent également changer.
Ici, dans la tache tu as ceci (une variable utilisé dans une PropertyPlaceHolder ) :
<property name="url" value="${${environnement}.url}"/> <br />
</bean>
Une fois importé, cette configuration donnerait ceci :
<property name="url" value="${environnement1.url}"/> <br />
</bean> <br />
<bean name="monitoringTask.environnement2" class="be.hikage.springtemplate.MonitoringTimerTask"> <br />
<property name="url" value="${environnement2.url}"/> <br />
</bean>
Une fois importé, le PropertyPlaceHolder va faire son travail et remplacer les valeurs provenant d’un fichier Properties.
C’est donc bien des « configuration » différentes mais dont la structure est similaire.
Il n’est donc pas possible d’utiliser des alias
Ah oui, je n’avais pas compris que c’était les noms des beans qui changeaient.
Mais c’est quand même curieux… qu’est-ce qui les a poussé à nommer les beans Scheduler.ENVIRONNEMENT1 dans un projet, Scheduler.ENVIRONNEMENT2 dans un autre, Scheduler.ENVIRONNEMENT3… ces beans ayant les mêmes valeurs ??
Je crois qu’il existe aussi un système d’alias dans spring : http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-beanname-alias
Peut être eut-il pu être utilisé ?
Ici le principe c’est que les fichiers monitoring-environnement1 et monitoring-environnement2 contiennent la meme structure de beans, mais pour lesquels les noms diffères.
Par exemple, le fichier 1 contiendra les beans :
Scheduler.ENVIRONNEMENT1
Trigger.ENVIRONNEMENT1
Task.ENVIRONNEMENT1
Et le fichier 2
Scheduler.ENVIRONNEMENT2
Trigger.ENVIRONNEMENT2
Task.ENVIRONNEMENT2
Mais avec les même configuration, etc .. en gros du copier/coller mais en changeant les noms.
Dans ce cas précis, il est plus intéressant d’avoir un seul fichier « modèle » configurant des beans
Scheduler.${environnement}
Trigger.${environnement}
Task.${environnement}
Et des les importer en spécifiant les variables.
L’intérêt est que si on devait avoir 10 environnements, la configuraiton serait centralisée dans un seul fichier et pas 10.
Il n’est pas possible d’utiliser l’ajout de plusieurs contextes (ou fichiers de contextes, je ne sais pas quelle est la bonne formule) ?
Il me semble que si vous donnez à lire à un contexte les fichiers ctx1.xml et ctx2.xml, le contexte contiendra les beans de ctx1.xml, modifiés par ceux de ctx2.xml.
Donc, on peut faire un ctx1.xml global, dont certains beans pourrant être modifiés par ctx2, arrivant à peu près au même résulat que vous, enfin il me semble.
Cela dit c’est vrai que cela demande un certain niveau d’organisation, par forcément présent lorsque on est en face de fichier type monitoring-environnement1.xml, monitoring-environnement2.xml…
Et je ne sais pas si ce que je dis est très clair ??