| Astuce | ||
|---|---|---|
| ||
Relecture RB faite le 16/02/2011 | ||
| Remarque | ||
Bon pour relecture |
Ce chapitre n'a pas la prétention d'être une formation à Spring (pour . Pour plus d'informations, vous pouvez vous reporter à une présentation de Spring en Français comme celle de Thierry Templier : http://www.springframework.org/node/155la documentation de springsource ( HTML / PDF ). Ne sont abordés ici que quelques éléments qui permettent détails permettant de mieux comprendre certains éléments des fichiers de configuration de esup-commons.
...
| Remarque |
|---|
Esup-commons V2 utilise Spring 3 |
Tout au long de ce chapitre nous allons nous appuyer sur un exemple (configuration du gestionnaire d'exceptions) :
| Bloc de code |
|---|
<bean id="exceptionServiceFactory" class="org.esupportail.formationcommons.services.exceptionHandling.CachingEmailExceptionServiceFactoryImpl" parent="abstractApplicationAwareBean"> <property name="doNotSendExceptionReportsToDeveloperssmtpService" valueref="falsesmtpService" /> <property name="smtpServicerecipientEmail" refvalue="smtpService"${exceptionHandling.email}" /> <property name="authenticationService" ref="authenticationService"/> exceptionViews"> <map> <entry key="java.lang.Exception" value="go_exception" /> </map> </property> <property name="recipientEmaillogLevel" value="webmaster@domain.edu"${exceptionHandling.logLevel}" /> <property name="cacheManager" ref="cacheManager" /> <property name="cacheName" value="" /> </bean> |
...
Sommaire :
| Sommaire | ||
|---|---|---|
|
...
Les fichiers de configuration
Spring permet de créer des objets (appelés alors beans) en les déclarant dans un fichier de configuration XML.
Le fichier de configuration principal (/properties/applicationContext.xml) est déclaré dans le *web.xml xml* sous la forme d'un paramètre de l'application :
...
Dans esup-commons ce fichier de configuration principal contient seulement des inclusions de fichiers de configurations configuration spécialisés par domaine, comme par exemple exemple:
| Bloc de code |
|---|
<import resource="exceptionHandling/exceptionHandling.xml" /> |
Il est possible, suivant les besoins de votre application, de supprimer ou d'ajouter des fichiers de configuration spécialisés.
L'injection de données
Une des caractéristiques de base de Spring est de permettre l'injection de données.
...
L'injection de données permet de renseigner des attributs d'un bean via un fichier de configuration. Le bean doit disposer d'un setter pour l'accès à ces attributs.
Voyons quelques exemples...
Injection d'une chaîne de caractères
| Bloc de code |
|---|
<property name="recipientEmail" value="webmaster@domain.edu"/> |
Dans ce cas, la méthode setRecipentEmail() sera appelée avec pour paramètre, la valeur webmaster@domain.edu.
Injection d'un autre bean
| Bloc de code |
|---|
<property name="authenticationService" ref="authenticationService"/> |
On voit ici un autre aspect important de Spring qui est l'utilisation quasi systématique des interfaces. La classe CachingEmailExceptionServiceFactoryImpl (qui correspond au bean exceptionServiceFactory et contient la définition de cette propriété authenticationService) a un attribut authenticationService de type AuthenticationService. AuthenticationService est une interface. Le bean authenticationService doit donc être d'une classe qui implémente cette interface. Ceci permet d'avoir plusieurs implémentations possibles de pour cette interface et de choisir, simplement en modifiant un fichier de configuration, laquelle on utilise. Cette approche est particulièrement intéressante . Elle : elle permet, par exemple, de très facilement tester une couche de l'application en branchant des implémentations de tests des autres couches avec lesquelles le bean doit interagir.
Injection d'une map
| Bloc de code |
|---|
<property name="exceptionViews">
<map>
<entry key="java.lang.Exception" value="go_exception" />
</map>
</property>
|
Injection d'une liste
| Bloc de code |
|---|
<property name="servers">
<list>
<ref bean="smtpServer1" />
<ref bean="smtpServer2" />
</list>
</property>
|
Utilisation de paramètres
Afin de centraliser la configuration, une bonne pratique consiste à utiliser un fichier de configuration regroupant les paramètres de l'application. Ceci évite notamment de devoir modifier n fichiers différents.
Exemple d'utilisation :
| Bloc de code |
|---|
<property name="recipientEmail" value="${exceptionHandling.email}" />
|
Ici la propriété recipientEmail contiendra la valeur contenue dans le paramètre exceptionHandling.email.
Le paramètre exceptionHandling.email est défini dans le fichier default.properties et peut être surchargé dans le fichier config.properties :
| Bloc de code |
|---|
exceptionHandling.email=bugs@domain.edu
|
| Remarque | ||
|---|---|---|
Ce mécanisme est rendu possible par la définition d'un bean utilisant la classe PropertyPlaceholderConfigurer de Spring dans le fichier properties/applicationContext.xml
Ici on définit les propriétés dans le fichier defaults.properties.Elles sont éventuellement écrasées par celles définies dans config.properties. Ici on utilise aussi la possibilité de surcharger ces valeurs par une référence à un fichier qui sera précisé par une option au lancement de la JVM (Ex : -Dapplication.config.location=/tmp/foo.properties). Afin que le propertyConfigurer ne lève pas une exception au cas où cette dernière possibilité n'est pas utilisée on positionne une des ces propriétés (ignoreResourceNotFound) pour qu'il ignore les éventuelles ressources absentes. |
L'héritage de configuration
Spring n'oblige pas à saisir, dans toutes les définitions de beans, les mêmes propriétés. Pour cela, il est possible d'utiliser le mot-clé parent.
Le « parent » à a un attribut abstract="true" car il ne doit pas être créé en mémoire par Spring. Cette notation permet de se rapprocher de l'héritage Java qui est beaucoup utilisé dans esup-commons.
Exemple d'un bean « parent » ayant aussi lui-même un « parent » « parent » :
| Bloc de code |
|---|
<bean
id="abstractApplicationAwareBean"
parent="abstractI18nAwareBean"
abstract="true">
<property name="applicationService" ref="applicationService" />
</bean>
|
| Remarque |
|---|
L'attribut scope (voir ci-après) n'est pas héritable, il est donc inutile de le préciser pour un bean abstrait. |
Vérification des beans
Les beans manipulés par Spring n'ont pas, par défaut, de dépendances particulières avec Spring.
Il est, par contre, possible de sciemment introduire une dépendance avec Spring pour obtenir des services supplémentaires.
Faire en sorte que votre bean implémente l'interface InitializingBean de Spring en fait partie. Cette interface vous oblige à implémenter une méthode afterPropertiesSet qui sera appelée par Spring juste après l'initialisation du bean. Cette méthode vous permet de vérifier que toutes les propriétés sont biens bien initialisées. Si ce n'est pas le cas, vous pouvez, par exemple, lever une exception ou affecter une valeur par défaut.
On trouvera par exemple exemple :
| Bloc de code |
|---|
public void afterPropertiesSet() {
super.afterPropertiesSet();
if (!StringUtils.hasText(exceptionView)) {
exceptionView = DEFAULT\__SERVLET_\_EXCEPTION_VIEW;
logger.info(getClass() + ": no exceptionView set, using default \[" + exceptionView + "\]");
}
}
|
Portée des beans
Spring (à partir de 2.0) offre une notion de portée (scope).
Par défaut, un bean est de portée singleton. Spring crée une seule instance de ce bean pour toute la durée d'exécution de l'application.
Il existe aussi des portées session et request qui, respectivement, permettent d'avoir une instance du bean par session utilisateur (au sens d'une application web) ou par requête (au sens HTTP). Cette notion est particulièrement intéressante pour les contrôleurs web d'une application. Les contrôleurs des applications web Ces derniers sont en général des beans de portée session, comme par exemple exemple :
| Bloc de code |
|---|
<bean id="administratorsController" class="[...].formation.web.controllers.AdministratorsController" parent="abstractContextAwareController" scope="session" /> |
Usuellement, un bean de scope request peut faire référence, via ses propriétés, à un bean de scope session ou singleton. De même, un bean de scope session peut faire référence à un bean de scope singleton. Une bonne architecture nous
...
amène d'ailleurs à utiliser dans ce sens l'injection de beans. Par défaut, la réciproque provoque une exception ... mais il est cependant possible de réaliser cette réciproque par le biais de l'aop, et cela très simplement.
Concrètement si nous voulons ici injecter le bean administratorsController qui est de scope session dans un bean de scope singleton, on utilisera la balise aop:scoped-proxy comme ceci dans la déclaration du bean administratorsController :
| Bloc de code |
|---|
<bean id="administratorsController"
class="[...].formation.web.controllers.AdministratorsController"
parent="abstractContextAwareController"
scope="session">
<aop:scoped-proxy/>
</bean>
|
Pour ce faire, on aura pris soin de déclarer comme il se doit l'espace de noms aop, avec dans la balise racine du fichier de
...
configuration de beans
...
Spring ceci :
| Bloc de code |
|---|
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" 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-2 3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-23.0.xsd" >Attention vous devez bien utiliser spring-beans-2.0.xsd et spring-aop-2 .0.xsd (-2.0.xsd pour les deux xsd).
</beans>
|
| HTML Comment |
|---|
Récupération des beans |
Il est possible de récupérer un bean à partir de son nom |
à partir du code JAVA. La classe BeanUtils fournie par esup-commons V1 n'est plus utilisée. On utilise un mécanisme interne à Spring basé sur l'implémentation de org.springframework.context.ApplicationContextAware esup-commons V2 fournit une telle implémentation qu'il suffit de déclarer dans un fichier de configuration Spring (ex : properties/applicationContext.xml) :
|
Depuis le code java, on utilisera :
|
...
|
...
|