Stripes avec Spring
Stripes est un framework d'application web conçu de façon à faciliter le développement web pour un maximum de productivité. Spring est, premièrement, un conteneur de composants légers (bien qu'actuellement il fasse beaucoup d'autres choses) Il est conçu pour sa facilité d'utilisation pour un maximum de productivité. Il paraît donc sûrement naturel de les utiliser ensemble.
Stripes s'intègre avec Spring afin de fournir à vos classes ActionBean
l'accès aux ressources Spring sous forme de beans Spring configurés. Il fait ceci avec une simple injection de beans Spring dans vos ActionBeans
sans que vous vous en rendiez compte. Il faudra un peu de configuration pour démarrer, mais une fois faite, vous pourrez utiliser vos beans Spring dans votre application web Stripes sans écrire une seule ligne de plus d'XML !
Installation et Configuration Spring
Cette partie apporte une vue d'ensemble basique de l'installation et de la configuration de Spring afin que vous puissiez l'intégrer avec votre application Stripes. Cette partie ne traitera pas toutes les façons possible de le faire, mais tout simplement une façon qui fonctionne. Commencez par télécharger la toute dernière version du Spring d'ici : http://www.springframework.org/download. Dézippez le fichier téléchargé et trouvez le fichier dist/spring.jar
. Puis copiez ce fichier dans le classpath de votre application, sûrement sous WEB-INF/lib
.
Affiner Votre classpath
Si le fait d'avoir beaucoup de classes inutiles dans votre classpath vous embête, vous préférerez peut-être prendre le temps d'étudier les jar spring-*
variés dans le répertoire dist
afin de rassembler le minimum dont vous avez besoin pour votre application. Moi, je suis trop paresseux pour le faire donc j'utilise spring.jar
qui contient plus que de nécessaire.
Une fois que le(s) jar(s) est (sont) en place il faut créer un fichier de contexte Spring, puis configurer le contexte web de l'application dans votre fichier web.xml
. Commençons d'abord par jeter un coup d'œil au web.xml
:
<listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-context.xml</param-value> </context-param>
Le contenu du listener
configure tout simplement une classe listener Spring, qui amorce Spring dans l'environnement de l'application web. Le context-param
fournit à Spring le paramètre de contexte afin qu'il puisse repérer le fichier contexte à utiliser. Dans notre cas nous avons spécifié /WEB-INF/spring-context.xml
. Peut importe le nom choisi, mais il est préférable que l'on place dans WEB-INF
ou dans un de ses sous-répertoires, pour s'assurer qu'il n'est pas accessible par des clients de votre application web !
Le deuxième chose qu'il faut faire est de configurer le contexte Spring. Pour plus de détails lisez la documentation Spring au http://www.springframework.org/docs/reference/index.html. Ce qui suit est un exemple qu'on pourrait utiliser afin d'accéder aux composants manager variés de l'application Bugzooky en tant que beans Spring.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" > <beans> <bean name="/bugzooky/BugManager" class="net.sourceforge.stripes.examples.bugzooky.biz.BugManager" /> <bean name="/bugzooky/PersonManager" class="net.sourceforge.stripes.examples.bugzooky.biz.PersonManager" /> <bean name="/bugzooky/ComponentManager" class="net.sourceforge.stripes.examples.bugzooky.biz.ComponentManager" /> </beans>
Configuration Stripes pour Spring
Maintenant que nous avons paramétré Spring nous avons besoin d'informer Stripes à propos de Spring. Dans votre web.xml
trouvez le paramètre d'initialisation du StripesFilter
. Si vous n'avez pas encore définit le paramètre Interceptor.Classes
, ajoutez ce qui suit :
<init-param> <param-name>Interceptor.Classes</param-name> <param-value> net.sourceforge.stripes.integration.spring.SpringInterceptor </param-value> </init-param>
Ce paramètre informe Stripes qu'il doit utiliser l'intercepteur Spring. Ceci fonctionne avec la version 1.5 de Stripes et les versions supérieures; si vous utiliser toujours une ancienne version, vous avez aussi besoin de dire à Stripes de ne pas arrêter d'utiliser l'intercepteur méthode Before
/After
(ce qui est configuré par défaut) :
<init-param> <param-name>Interceptor.Classes</param-name> <param-value> net.sourceforge.stripes.integration.spring.SpringInterceptor, net.sourceforge.stripes.controller.BeforeAfterMethodInterceptor </param-value> </init-param>
Nous avons fini d'installer et de bidouiller avec les configurations. Codons un peu !
Accéder aux Beans Spring dans vos ActionBeans
Stripes utilise le SpringInterceptor afin d'injecter des beans Spring dans des ActionBeans
après que l'ActionBean
soit instancié. Pour ce faire, il faut expliquer comment injecter les beans et quoi injecter. Plutôt que de spécifier la configuration dans un fichier XML, on utilise une simple annotation. Un cas typique ressemblerait à quelque chose comme ceci :
/** Permet au BugManager d'être injecté. */ @SpringBean("/bugzooky/BugManager") public void injectBugManager(BugManager bm) { this.bm = bm; }
Spécifier le nom exact et chemin du bean Spring que vous voulez injecter est probablement la façon la plus sûre. Toutefois il en existe deux autres: appelons les auto-wire par nom et auto-wire par type. Si vous omettez la valeur de l'annotation @SpringBean
de cette manière :
/** Permet au BugManager d'être injecté. */ @SpringBean protected void setBugManager(BugManager bm) { this.bm = bm; }
Alors, à ce moment-là, Stripes tentera d'abord d'auto-wire (auto-lien) par nom, puis par type. Tout d'abord le nom du bean désiré est dérivé du nom de la méthode - si le nom de la méthode commence par 'set', il sera enlevé et le prochain caractère sera mis en minuscule (suivant les conventions JavaBean), sinon le nom entier de la méthode sera pris tel que. Dans l'exemple ci-dessus setBugManager
produit bugManager
. Le contexte Spring est ensuite interrogé afin de voir s'il contient un bean appelé bugManager
. Cette interrogation n'est pas sensible à la casse ni au chemin, ce qui donne le résultat du bean /bugzooky/BugManager
de l'exemple ci-dessus.
Si le contexte ne contient pas de bean avec le même nom, l'auto-wire par type est la dernière chance. Dans ce cas, si un seul bean existe dans le contexte du type requit par la méthode annotée (BugManager
dans ce cas), le bean sera sélectionné puis injecté dans l'ActionBean
.
Un détail mérite notre attention: même si des ActionBeans
eux-mêmes ne sont pas des beans Spring, avec cette approche, les beans injectés du contexte Spring sont complètement gérés par Spring et ont accès à tous les services Spring comme n'importe quel autre bean Spring.
Les Méthodes Get/Set pour beans Spring pourraient être Dangereuses
Vu que Stripes dérive des paramètres de requête et place les propriétés dans des ActionBeans
par nom, il est extrêmement imprudent de fournir des méthodes public
qui correspondent aux sémantiques des propriétés JavaBean pour des beans Spring (ex. public void setBugManager(...)
). Ceci permettrait à des utilisateurs malveillants de rendre vos beans Spring null
, ou peut-être même d'assigner des valeurs de sous-propriétés si le bean lui-même fourni des méthodes get
/set
.
La possibilité que cela se passe est très faible - il faudrait qu'un utilisateur malveillant devine correctement que vous utilisez Spring, les noms des méthodes qui accèdent au beans Spring, et les propriétés de vos beans Spring. Mais cela est théoriquement possible, donc autant limiter les risques (surtout que c'est très facile à faire).
Stripes fournit plusieurs alternatives. Si vous voulez auto-wire par nom, il suffit simplement d'enlever le set
du nom de la méthode, par ex. public void bugManager(BugManager bm)
. Si vous nommez explicitement vos beans Spring avec @SpringBean("/tel/nom")
alors vous pouvez simplement nommer vos méthodes autrement, ex. injecterTelManager()
. Ou même encore, comme expliqué plus bas, vous pouvez rendre les méthodes protected
ou private
et/ou mettre l'annotation directement sur les champs afin d'injecter vos beans Spring.
Injection par Méthode vs. par Champ
Stripes peut injecter des beans Spring autant par méthode que par champ. Le type d'accès est déterminé par le placement de l'annotation @SpringBean
. Si l'annotation est directement sur un champ, ex.
@SpringBean private BugManager bugManager;
alors Stripes utilisera l'accès par champ. Si l'annotation est sur une méthode, ex.
@SpringBean protected void setBugManager(BugManager bm) { ... }
alors Stripes utilisera la méthode afin d'injecter le bean.
Si le gestionnaire de sécurité de la JVM le permet, Stripes injectera même des beans Spring, à la demande, dans les champs et méthodes protégés, privés et ceux avec l'accès par défaut. Si le gestionnaire de sécurité de la JVM ne le permet pas, une exception qui explique le problème sera levée.
Utiliser des Beans Spring dans d'Autres Types d'Objets
Il arrive parfois que vos ActionBeans
ne soient pas les seuls types de classes qui sont gérés par Stripes mais que eux aussi aient besoin d'avoir des beans Spring injectés. Les intercepteurs en ont souvent besoin, mais surtout si vous finissez par outrepasser n'importe quel Composant Configurable Stripes, vous souhaiterez peut-être lui injecter des beans Spring.
Heureusement, ceci est facile à faire. Dans le cas des intercepteurs il existe une classe mère qui peut être étendue : SpringInterceptorSupport qui est une simple classe mère qui s'injecte des beans Spring au moment de son initialisation.
Pour d'autres classes, la solution est presque aussi simple. Une classe qui s'appelle SpringHelper fournit des méthodes afin d'appliquer le même mécanisme d'injection de beans Spring à n'importe quel objet pourvu que vous ayez accès à l'ActionBeanContext
, au ServletContext
ou à l'ApplicationContext
de Spring. Normalement il suffit d'écrire :
SpringHelper.injectBeans(obj, StripesFilter.getConfiguration().getServletContext());