juin
2008
Spring peut facilement être intégré à une application JSF (voir ce billet).
Ainsi, Les managed-beans de JSF pourront disposer des fonctionnalités offertes par Spring et spécialement la DI (Dependancy Injection) via l’utilisation des EL dans faces-config.xml.
Avec la version 2.5, Spring permet d’aller encore plus loin en prenant en charge la gestion complète des managed beans de JSF.
Pour ce faire, il
faut comme d’habitude déclarer le chargeur de contexte de Spring dans le web.xml, comme ceci:
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Ensuite, on applique au contrôleur une autre annotation comme-ci:
@Controller
@Scope("request")
public class TestCtrl
:
:
>
Il faut aussi créer l’habituel applicationContext.xml dans WEB-INF:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd>
<!--
Active la prise en charge par Spring de diverses annotations.
-->
<context:annotation-config />
<!--
Active le scan par Spring des beans pour diverses annotations.
On spécifie le package de base où effectuer le scan.
-->
<context:component-scan base-package="org.djo.control" />
</beans>
On passe à l’étape suivante (montré dans un précédent billet): L’intégration de Spring dans faces-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<application>
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver
</el-resolver>
</application>
</faces-config>
On crée ensuite un contrôleur (le feu managed-bean):
@Controller("test")
package org.djo.control;
public class TestCtrl {
private String msg = "Hello ";
//getter et setter de msg
}
Remarquez l’annotation @Controller (stéréotype dans la terminologie Spring) qu’on a appliqué à cette classe.
Cette annotation sera interceptée par Spring (grâce à l’élément component-scan décrit plus haut et le cycle de vie de ce bean sera alors géré par Spring et non plus par l’implémentation JSF.
Ce bean sera alors exposé aux pages JSF (et partout ailleurs, comme tout autre bean managé par Spring) mais disposera en plus de tous ce que Spring offre comme la DI et la gestion des transactions, des annotations JSR 250 (gestion du lifecycle), etc.
On peut faire le test suivant dans une page JSF:
<h:outputText value="#{test.msg}" />
On aura « Hello » comme résultat si tout va bien.
Approfondissons encore la chose !
La première question qui se pose est comment contrôler le scope du contrôleur ?
Par défaut, il s’agit du scope Singleton (equivalent à ApplicationScope).
Pour pouvoir utiliser les scopes ordinaires du web (request et session), il faut déclarer un autre listener dans le web.xml:
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Il suffit ensuite d’ajouter l’annotation @Scope pour contrôler finement le scope d’un contrôleur:
@Controller
@Scope("request")
public class TestCtrl
:
:
Vous pouvez utiliser les scopes suivants:
- singleton
- prototype
- session
- request
Remarquez que de cette façon, il devient complètement inutile de déclarer les contrôleurs dans faces-config.xml.
Etant managé par Spring, il devient possible d’utiliser les annotations de la JSR 250 comme @PostConstruct et @PreDestroy.
Une méthode annotée avec @PostConstruct est appelée automatiquement par Spring suite à l’instantiation du bean et la satisfaction de toutes ses dépendances et une méthode annotée avec @PreDestroy est appelée automatiquement par Spring avant la destruction du bean.
La première annotation est utile par exemple dans le scénarion suivant:
Le contrôleur déclare un champ EntityDao (un DAO) comme dépendance et possède une liste List<Entity> qu’il expose aux pages JSF.
Le contrôleur ne peut pas utiliser le DAO pour initialiser la liste dans le constructeur vu que le DAO n’est pas encore injecté.
La solution est alors de le faire dans une méthode annotée avec @PostConstruct.