Vous êtes sur la page 1sur 105

Formation 

: Développement JEE avec Spring

FRAMEWORK SPRING

Octobre 2020

SOMMAIRE
1. Introduction à Spring..................................................................................................................................5
Introduction....................................................................................................................................................................................................................5
1
Formation  : Développement JEE avec Spring

Pré-requis........................................................................................................................................................................................................................5
1.1 Historique de Spring..........................................................................................................................................................................................5
1.2 Spring et J2EE.....................................................................................................................................................................................................7
1.3 Les modules Spring.............................................................................................................................................................................................8
1.4 Concept de Beans...............................................................................................................................................................................................9
1.5 Le contexte d'application Spring...................................................................................................................................................................9
1.6 Conception de Beans........................................................................................................................................................................................10
1.6.1 Déclarer des beans...................................................................................................................................................................................10
1.6.2 Configurer le contexte.............................................................................................................................................................................11
1.6.3 Chargement d’un contexte.....................................................................................................................................................................11
1.6.4 Récupération d’une référence d’un Bean...........................................................................................................................................11
1.6.5 Constructeurs.............................................................................................................................................................................................12
1.6.6 Configuration de bean dans le cas de l’héritage.............................................................................................................................13
1.6.8 Injection de dépendances.......................................................................................................................................................................15
1.6.9 Chargement et utilisation de propriétés dans un bean..................................................................................................................23
1.6.10 Portée des beans (scoping).................................................................................................................................................................23
1.6.11 Les espaces de nommage.....................................................................................................................................................................26
1.6.12 Initialisation et destruction de beans.............................................................................................................................................28
1.6.13 Injection dans les propriétés des beans.........................................................................................................................................28
1.6.14 Référencer d’autres beans.................................................................................................................................................................28
1.6.15 La liaison automatique inter beans (Auto-wiring).......................................................................................................................28
2 Accès aux bases de donnés.........................................................................................................................31
2.1 Accès par JDBC..................................................................................................................................................................................................31
b) Dépendances du projet...................................................................................................................................................................................31
2.2 Accès par JdbcTemplate................................................................................................................................................................................38
2.3 Intégration de Spring avec Hibernate.......................................................................................................................................................39
3 Gestion des transactions............................................................................................................................43
3.1 Tour d'horizon des gestionnaires de transactions indépendants...............................................................................................................43
3.2 Implémentation d'un scénario "Two phase-commit" avec Atomikos.............................................................................................................44
b) Configuration et codage de l'application........................................................................................................................................................48
Les tests.......................................................................................................................................................................................................................55
Classe de Services........................................................................................................................................................................................................55
Transactions entre 2 bases de données........................................................................................................................................................................58
2
Formation  : Développement JEE avec Spring

Transaction entre 1 base de données et un broker JMS...............................................................................................................................................60


3.2 La propagation des transactions.................................................................................................................................................................62
3.3 L'utilisation des transactions de manière déclarative.............................................................................................................................63
3.4. La déclaration des transactions dans la configuration du contexte...........................................................................................................63
3.5 Un exemple de déclaration de transactions dans la configuration.............................................................................................................68
3.6 La déclaration des transactions avec des annotations..................................................................................................................................74
3.7 L'utilisation de l'annotation @Transactional.....................................................................................................................................................76
3.8 Le support de @Transactional par AspectJ.......................................................................................................................................................78
3.9 Un exemple de déclaration des transactions avec des annotations.....................................................................................................78
3.10. La gestion du rollback des transactions.........................................................................................................................................................85
3.11 La gestion du rollback dans la configuration............................................................................................................................................85
3.13 La gestion du rollback avec les annotations...................................................................................................................................................87
3.15. La mise en oeuvre d'aspects sur une méthode transactionnelle........................................................................................................87
3.16 L'utilisation des transactions via l'API..............................................................................................................................................................92
3.17 L'utilisation de la classe TransactionTemplate......................................................................................................................................92
3.18 L'utilisation directe d'un PlatformTransactionManager...............................................................................................................................97
4 Scheduler...............................................................................................................................................99
4.1 Définition d’une tache programmée (Scheduler Task)...........................................................................................................................99
Conclusion.................................................................................................................................................................................................................101
Configuration des clients...........................................................................................................................................................................................102
5 Intégration de Spring...............................................................................................................................103
6 Mise en place d’un environnement de développement Java/Eclipse/Maven...........................................................103
6.1 Création d’un projet Maven/Eclipse pour Spring 2.5...........................................................................................................................103

3
Formation  : Développement JEE avec Spring

1. Introduction à Spring
Introduction
Spring est un framework Java écrit par un groupe de programmeurs chevronnés, afin de simplifier le processus de développement des applications d’entreprise.
Ce framework peut être vu comme une boite à outils, constituée d’un ensemble d’API, qui offre des moyens de:
- Concevoir une application basée sur POJO (plain old Java objects). Remarque : Un POJO est une classe Bean Java
- Réduire le couplage grace à l’injection de dépendences et une conception applicative orientée interface
- Utilisation de la programmation déclarative
- Réduction des temps de développement par l’utilsiation des templates

Pré-requis
Afin de d’utiliser le framework Spring, il est indispensable d’avoir des connaissances de base du langage de programmation Java, et idéalement maitriser un IDE tel que
Eclipse.

1.1 Historique de Spring


Le framework Spring a été initialement développé par Rod Johnson et Juergen Holler. Spring a connu plusieurs versions :
 Spring 1.0 : mars 2004
 Spring 1.1 : septembre 2004
 Spring 1.2 : mai 2005
 Spring 2.0 : octobre 2006
 Spring 2.5 : novembre 2007
 Spring 3.0 : décembre 2009
 Spring 3.1 : courant 2011
Spring 1.0 implémente les fonctionnalités de base du framework :
 le conteneur qui implémente le motif de conception IoC
 le développement orienté POJO
 l'AOP par déclaration
 le support de JDBC, ORM et frameworks Web
 la configuration XML basée sur une DTD
4
Formation  : Développement JEE avec Spring

Spring 1.2
 support de JMX
 support JDO 2, Hibernate 3, TopLink
 support de JCA CCI, JDBC Rowset
 déclaration des transactions avec @Transactional
Spring 2.0 apporte de nombreuses nouveautés :
 le support et l'utilisation d'AspectJ
 la configuration XML basée sur un schéma XML
 des simplifications de la configuration notamment avec des namespaces dédiés (beans, tx, aop, lang, util, jee, p)
 les Message Driven POJO
 les annotations @Repository, @Configurable
Spring 2.5 apporte de nombreuses nouveautés pour faciliter sa configuration :
 l'ajout de nouveaux namespaces (context, jms) avec de nouveaux tags
 l'enrichissement des namespaces existants (jee, aop)
 l'ajout d'annotations concernant le cycle de vie des beans (@Service, @Component, @Controller), autowiring (@Autowired, @Qualifier, @Required), la gestion des
transactions (@Transactional) et support des annotations standards de Java 5 (@PostConstruct, @PreDestroy, @Resource)
 les tests d'intégration reposant sur Junit 4 et des annotations (@ContextConfiguration, @TestExecutionListeners, @BeforeTransaction, @AfterTransaction)
Spring 3.0 apporte de nombreuses nouveautés pour sa configuration et les fonctionnalités proposées :
 des possibilités enrichies de configurer le context en utilisant des annotations : annotations issues du projet Spring JavaConfig qui sont ajoutées dans Spring Core
(@Configuration, @Bean, @DependsOn, @Primary, @Lazy, @Import, @ImportResource et @Value)
 Spring Expression Langage (SpEL) : un langage d'expressions utilisable pour la définition des beans dans Spring Core et pour certaines fonctionnalités dans des projets du
portfolio
 le support de REST
 Object to XML Mapping (OXM) : abstraction pour utiliser des solutions de mapping objet/XML initialement proposée par le projet Spring Web services et intégrée dans
Spring Core
 requiert un Java SE 5.0 ou supérieur (refactoring des API pour une utilisation des generics, des varargs, de java.util.concurrent, ...)
 une nouvelle modularisation : la distribution de Spring en jar a été revue pour que chaque module ait son propre jar. L'archive spring.jar n'est plus proposée
 le support de moteurs de bases de données embarquées (Derby, HSQL, H2)

5
Formation  : Développement JEE avec Spring

 le support de la validation (JSR 303), du data binding et de la conversion de type


 le support JSR 330
 le scheduling par configuration, annotations (@Async, @Scheduled) ou API
 l'ajout de nouveaux namespaces (task, jdbc, mvc)
 la compatibilité forte avec Spring 2.5
 le support de l'API Porlet 2.0 par Spring MVC
Spring 3.1 :
 support des conversations
 support des caches
 ajout de la notion de profile qui permet d'avoir des configurations du context différentes pour chaque environnement
 ajout de nouvelles annotations pour définir certaines fonctionnalités de namespaces dans la configuration
 support des servlets 3

1.2 Spring et J2EE


Spring est né de l'idée de fournir une solution plus simple et plus légère que celle proposée par Java 2 EE. C'est pour cette raison que Spring a été initialement désigné comme un
conteneur léger (lightweight container).
L'idée principale de Spring est de proposer un framework qui utilise de simples POJO pour développer des applications plutôt que d'utiliser des EJB complexes dans un conteneur.
Spring ne respecte pas les spécifications de Java EE mais il intègre et utilise de nombreuses API de Java EE (Servlet, JMS, ...). Spring propose aussi une intégration avec certains
composants de Java EE notamment les EJB.
Java EE utilise une approche convention over configuration : par exemple, les EJB sont par défaut transactionnels. Spring utilise une approche ou la configuration doit être
explicite.
Spring est de plus en plus controversé notamment à cause de son empattement et à sa complexité croissante. De plus, face à la simplification engagée par Java EE à partir de sa
version 5 et à l'ajout de l'injection de dépendances dans Java EE 6, le choix entre Java EE et Spring n'est plus aussi facile.

6
Formation  : Développement JEE avec Spring

1.3 Les modules Spring


Spring regroupe un ensemble de modules :

a) Core du conteneur Spring


Il s’agit du module noyau de Spring, qui prend en charge la creation, configuration et gestion des beans à l’intérieur du conteneur. Le point d’entrée principal est une factory
de beans Spring, qui est la partie qui traite l’injection de dépendances. En se basant sur cette factory de beans ( Voir Design Pattern – Factory ), plusieurs implementations
de contextes d’application sont offertes (chacune offre un moyen de configurer Spring).
En plus de l’application contexte, et du la factory de beans, ce module fournit également plusieurs services tels que l’accès JNDI, l’intégration d’EJB, le scheduling et l’accès
à l’API email.

b) Intégration et accès aux données


Le module JDBC et DAO (accès aux données objets) de Spring simplifie le développement d’applications de type bases de données. Ceci, par exemple, en fournissant des
messages d’erreurs plus simples à interpréter que les codes erreurs provenant du moteur de base de données.
Il est également prévu l’intégration des principaux ORM (object-relational mapping (ORM) / frameworks de mapping objets/relationel) du monde Java, tels que Hibernate,
Java Persistence API, Java Data Objects, et iBATIS SQL Maps (avec support de la gestion des transactions)

c) Module AOP de Spring


L’AOP (Aspect Orienting Programming) est implémenté dans Spring à travers un module spécialisé. L’AOP est un moyen de réduire le couplage entre les objets d’une
application. Par exemple, les besoins de sécurité et les aspects transactionnels sont traités par l’AOP, indépendamment des objets sur lesquels ils interviennent.

d) WEB et REMOTING
Le paradigme Model-View-Controller (MVC) est l’approche la plus communément utilisée pour la conception d’application web, ce qui garantit une stricte separation entre
l’interface utilisateur et la logique applicative. Il existe en Java de nombreux frameworks MVC, tells que Apache Struts, JSF, WebWork, etTapestry (qui implémentent tous
l’approche MVC).
Spring implémente une couche web spécifique, à travers un framework basé sur une servlet (pour les applications web conventionnelles/classiques)  ; et un autre pour le
développement d’application portels (en s’appuyant sur l’API Java Portlet).
En plus des applications web (partie interface utilisateur), ce module offre des solutions pour les traitements distants, afin d’interagir avec d’autres applications. Les
capacités de Spring en termes de remoting (traitements distants) incluent Remote Method Invocation (RMI), Hessian, Burlap, JAX-WS, et l’invocateur HTTP spécifique à
Spring’.

7
Formation  : Développement JEE avec Spring

e) Tests
Compte-tenu de l’importance des tests écrits par le développeur, Spring a prévu un module dédié aux tests (JNDI, servlets, and portlets). Au niveau de la phase des tests
dintégration, ce module fournit une prise en charage du chargement de beans dans le contexte d’application Spring.

1.4 Concept de Beans


Du point de vue du framework Spring, tous les objets sont beans. L’étape initiale avant d’utiliser Spring est de definir quels sont les objets qui devront être considérés
comme des Bean.
Un Beans n’est qu’une instance d’une classe (un objet) qui sera créée par le framework Spring, en se basant sur une description, appelée «  Application Context », ou
contexte de l’application. Le contexte de l’’application contient des méta données de configuration.
L’étape suivante va amener Spring à établir un plan de création des objets qui seront instanciés, quelles sont les dépendances qui seront injectées, les portées (scopes) des
différents Beans, à partir des méta-données de configuration (qui sont sauvegardées dans un fichier XML).
A partir de la version 3.0 de Spring, il est désormais possible d’utiliser des annotations au lieu d’un fichier XML pour definir des méta-données (ou contexte d’application).
Remarques :
Un Bean Spring doit respecter les règles suivantes :
- Il doit être matérialiser par une classe publique Java
- La classe peut avoir un constructeur public
- Les données membres (attributs) doivent avoir un niveau de visibilité égale à private
- Pour chaque donnée membre, il doit exister une méthode setter (pour l’accès en écriture d’une propriété) et une méthode getter (méthode de lecture de valeur d’une
propriété)

1.5 Le contexte d'application Spring

8
Formation  : Développement JEE avec Spring

Dans une application basée sur Spring, les objets sont gérés par le conteneur Spring. Ce conteneur prend en charge tous les aspects liés aux différents objets ( beans), à leurs
dépendances, à leur configuration respective, et la gestion de leur cycle de vie.
Dans Spring, cette gestion des beans est réalisée avec la notion de contexte d’application (Application context). Le contexte d’application permet à Spring de créer,
configurer et lier les différents objets (ou beans), en utilisant l’injection de dépendances, pour lier les différents composants d’une application.
L’avantage de cette approche est de simplifier la compréhension d’une application, de garantir une meilleure réutilisation, et permettre les tests unitaires.

1.6 Conception de Beans


Ce paragraphe va décrire la marche à suivre pour définir un Bean Spring.
1.6.1 Déclarer des beans
La première étape va consister à créer l’interface du Bean. Cette interface va définir un contrat qui sera implémenté par la classe du Bean.

a) Interface du bean
package org.formation.spring;
import org.formation.spring.exception.ComtabiliteException;

public interface TraitementComptable


{
public void enregistrerPiece(int mois, int exercice, String numero) throws ComptabiliteException;
}

b) Implémentation d’un bean


La

package alti.formation.spring;
public class TraitementComptableImpl implements TraitementComptable
{
public void enregistrerPiece(int mois, int exercice, String numero) throws ComptabiliteException
{
// implémenter la méthode
}

9
Formation  : Développement JEE avec Spring

1.6.2 Configurer le contexte


La configuration du contexte de l’application de Spring requiert que l’on crée un fichier XML, contenant un descriptif de chaque Bean. L’en-tête du fichier contient des
références à des fichiers XSD (grammaires XML) qui valide le contenu.
Remarque : Les fichiers XSD sont inclus dans les JAR du framework (localisés dans le classpath).

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
<bean id="..." class="...">
<!-- configuration et description des dependances -->
</bean>
<bean id="...' class="...">
<!-- configuration et description des dependances -->
</bean>
</beans>

La definition d’un bean nécessitera que l’on insére une balise <bean> dans le bloc parent <beans>

1.6.3 Chargement d’un contexte


Le chargement d’un contexte d’application Spring se fait de la manière suivante:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

ApplicationContext context = new ClassPathXmlApplicationContext("./applicationContext.xml");

1.6.4 Récupération d’une référence d’un Bean


Il est possible de définir une dépendance entre deux beans par le biais des références.
Exemple :

10
Formation  : Développement JEE avec Spring

Classe GestionComptabilite  :

package alti.formation.spring;

public class GestionComptabilite


{
public void creerPiece(String numero, int exercice, int mois)
{

}
}

Classe GestionReferentiel  :
package alti.formation.spring;

public class GestionReferentiel


{
private GestionComtabilite gestionComptable;

public void setGestionComptabilite()


{
}

Public GestionComptabilite getGestionComptabilie()


{
}
}

Le fichier du contexte applicationContext de Spring:

<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<bean id="premierBean" class="alti.formation.spring.GestionComptabilite ">
</bean>

<bean id="secondBean" class="alti.formation.spring.GestionReferentiel">


<property name="gestionComptable" >
<ref bean="premierBean"/>
</property>
</bean>
 
</beans>
11
Formation  : Développement JEE avec Spring

1.6.5 Constructeurs
Il est possible d’intervenir dans un fichier de configuration de Spring pour renseigner des valeurs qui seront utilisées lors de l’instanciation du bean.
Exemple:

<bean id="archivage" class="alti.spring.formation.Archivage">


<constructor-arg index=”0” value="15"/>
<constructor-arg index=”1” value="c:\\repertoire"/>
</bean>

1.6.6 Configuration de bean dans le cas de l’héritage


Dans Spring, l’héritage est défini dans le contexte de l’application des beans afin de partager des valeurs, des propriétés ou des configurations. Un bean enfant (ou qui dérive
d’un autre bean) héritera des propriétés et configurations de son parent. Comme dans le cas d’une classe java ordinaire, les beans enfants peuvent redéfinir les valeurs
héritées.

Exemple:

Contenu de la classe Client:

package alti.formation.spring;
 
public class Client
{
 
private int type;
private String action;
private String pays;
// méthodes getters et setters pour chaque attribut
}

Configuration du contexte de Spring (fichier applicationContext.xml) :

<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
12
Formation  : Développement JEE avec Spring

 
<bean id="clientAlgerieBean" class="alti.formation.spring.Client">
<property name="pays" value="Algerie" />
</bean>
 
<bean id="clientBean" parent="clientAlgerieBean ">
<property name="action" value="achat" />
<property name="type" value="1" />
</bean>
 
</beans>

Remarques:
Dans l’exemple ci-dessus, le bean clientBean contient l’initialisation des proprieties type et action, qui sont héritées du bean clientAlgerieBean.

Contenu du code Java d’exécution:

package alti.formation.spring;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class App
{
public static void main( String[] args )
{
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
 
Client client = (Client)context.getBean("clientBean");
System.out.println(cust);
 
}
}

Lors de l’exécution, le résultat affiché à l’écran est:

Client [type=1, action=achat, Pays=Algérie]

Remarque: Le bean clientBean hérite la propriété pays de son parent (bean clientAlgerieBean).

13
Formation  : Développement JEE avec Spring

1.6.7 Prise en charge d’un héritage avec une classe abstraite

Il est possible de definir dans un contexte d’application un heritage entre beans, en utilisant une classe abstraite comme classe de base. Exemple :

<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<bean id="ClientAbstraitBean" class="alti.formation.spring.ClientAbstrait" abstract="true">
<property name="pays" value="Algérie" />
</bean>
 
<bean id="ClientBean" parent="ClientAbstraitBean" class="alti.formation.spring.Client">
<property name="action" value="achat" />
<property name="type" value="1" />
<property name="pays" value="Tunisie" />
</bean>
 
</beans>

Commentaire:
Le bean ClientBean utilise la redéfinition (override) du bean parent abstrait ClientAbstraitBean

1.6.8 Injection de dépendances


a) Injection de valeurs
Dans Spring, les propriétés des bean peuvent être configurées grâce à l’élément <property> . Cet élément est semblable à <constructor-arg>, sauf qu’au lieu d’injecter des
valeurs d’arguments de constructeur, l’élément <property> invoque la méthode setter de la propriété correspondante.
Exemple:
Soit la definition de l’application context suivante :

<bean id="calcul" class="alti.formation.spring.Calcul">


14
Formation  : Développement JEE avec Spring

<property name="nom" value="test1"/>


</bean>

Une fois que le bean Calcul est instancié par Spring, ce dernier utilise la méthode setter pour injecter la valeur test1 à la propriété nom du bean.
Remarque :
L’injection de valeurs de propriétés ne se limite pas au chaines de caractères (String) mais peut aussi concernes des types (boolean, int, float, java.lang.Double, etc..) .

Exemple d’injection d’une valeur entière dans un bean :


<bean id="calcul" class="alti.formation.spring.Calcul">
<property name="nom" value="test1"/>
<property name="ecart" value="10"/>
</bean>

Remarque:
En fonction du type de la propriété, Spring effectuera la conversion adéquate.

b) Injection de références
Dans la definition d’un contexte d’application, il est possible de definer l’injection de references. L’exemple ci-dessous illustre la méthode à utiliser:

Contenu de l’interface : Reporting


package alti.formation.spring;

public interface Reporting


{
public void generer() throws Exception;
}

15
Formation  : Développement JEE avec Spring

Contenu de la classe: ReportingComptable


package alti.formation.spring;

public class ReportingComptable implements Reporting


{
public ReportingComptable() { }

public void generer() throws Exception


{
System.out.println("generer…");
}
}

Contenu de la classe: Composant


package alti.formation.spring;

public class Composant


{
private Reporting reporting;

public void setReporting(Reporting reporting) { this.reporting = reporting; }


public Reporting getReporting() { return this.reporting; }
}

Définition du contexte de l’application:


<bean id="reportingBean" class="alti.formation.spring.ReportingComptable"/>
<bean id="composantBean" class="alti.formation.spring.Composant">
<property name="reporting" ref="reportingBean"/>
</bean>

Remarques:
16
Formation  : Développement JEE avec Spring

D’un point de vue conceptuel, l’utilisation d’une référence vers une interface dans la classe Composant permet de réduire le couplage, et de faciliter ainsi toute
modification ultérieure, pour peu que l’on fournisse une instance d’une classe qui implémente l’interface Reporting. Spring encourage fortement l’utilisation de ce principe
dans le développement et les tests des applications.

Le code Java qui permet de mettre en relief l’intérêt de cette approche est le suivant :

ApplicationContext contexte=new ClassPathXmlApplicationContext("applicationContextl.xml");


Composant composant=(Composant) contexte.getBean("composantBean");
Reporting reporting = composant.getReporting() ;
reporting.generer();

c) Injection de structures de données (List, Map, Set)


A l’instar des propriétés, et des références, il est également possible en Spring d’injecter des collections.
Exemple détaillé :
Pour les besoins de l’exemple, nous définissons les classes Entreprise, et Personnel
Code source de la classe Entreprise :

package alti.formation.spring;
 
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
17
Formation  : Développement JEE avec Spring

 
public class Entreprise
{
private List<Object> collaborateurs;
private Set<Object> cadres;
private Map<Object, Object> dirigeants;
private Properties contacts;
. . .
}

Code source de classe Personne :

package alti.formation.spring;
 
 
public class Personne
{
private int age ;
private String nom;
private String adresse;
. . .
}

Le contenu du fichier de configuration du contexte Spring est :


<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<bean id="EntrepriseBean" class="alti.formation.spring">
 
<!-- java.util.List -->
<property name="collaborateurs">
<list>
<value>1</value>
<ref bean="PersonneBean" />
<bean class="alti.formation.spring.Personne">
<property name="nom" value="untel1" />
<property name="adresse" value="adresse1" />
18
Formation  : Développement JEE avec Spring

<property name="age" value="35" />


</bean>
</list>
</property>
 
<!-- java.util.Set -->
<property name="cadres">
<set>
<value>1</value>
<ref bean="PersonneBean" />
<bean class="alti.formation.spring.Personne">
<property name="nom" value="untel2" />
<property name="adresse" value="adresse2" />
<property name="age" value="40" />
</bean>
</set>
</property>
 
<!-- java.util.Map -->
<property name="dirigeants">
<map>
<entry key="Key 1" value="1" />
<entry key="Key 2" value-ref="PersonneBean" />
<entry key="Key 3">
<bean class="alti.formation.spring.Personne">
<property name="nom" value="untel3" />
<property name="adresse" value="adresse3" />
<property name="age" value="58" />
</bean>
</entry>
</map>
</property>
 
<!-- java.util.Properties -->
<property name="contacts">
<props>
<prop key="admin">admin@entreprise.dz</prop>
<prop key="support">support@entreprise.dz</prop>
</props>

19
Formation  : Développement JEE avec Spring

</property>
 
</bean>
 
<bean id="PersonneBean" class="alti.formation.spring.Personne">
<property name="nom" value="nom1" />
<property name="adresse" value="adresse1" />
<property name="age" value="50" />
</bean>
 
</beans>

Le code Java d’exécution est le suivant:

20
Formation  : Développement JEE avec Spring

package alti.formation.spring;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class Application
{
public static void main( String[] args )
{
ApplicationContext context = new ClassPathXmlApplicationContext("contexte.xml");
 
Entreprise entreprise = (Entreprise) context.getBean("EntrepriseBean");
System.out.println(cust);
 
}
}

L’affichage de la console est :

Client [
 
collaborateurs=[
1,
Personne [adresse=adresse1, age=35, nom=untel1],
],
 
dirigeants={
key 1=1,
key 2=Personne [adresse=adresse1, age=50, nom=nom1],
key 3=Personne [adresse=adresse3, age=58, nom=untel3]
},
 
contacts{admin=admin@nospam.com, support=support@nospam.com},
 
cadres=[
1,
Personne [adresse=adresse2, age=40, nom=untel2],
]

21
Formation  : Développement JEE avec Spring

d)

1.6.9 Chargement et utilisation de propriétés dans un bean


Il est également possible de définir le chargement d’un fichier properties localisé dans le classpath de l’application :

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
<property name="location" value="classpath:parametres_applicatifs.properties"/>
</bean>

1.6.10 Portée des beans (scoping)


Dans le framework Spring, tous les beans ont une portée de type Singleton. Lorsque le conteneur renvoit une référence vers un bean, il renvoie toujours la meme reference
(instance). Mais, parfois il est nécessaire de definer un autre type de portée (scope). Pour cela, Spring a prévu les portées suivantes :
singleton portée qui permet de référencer une seule instancer (portée par defaut utilisée par le conteneur Spring).
prototype intialisera une instance par utilisation (une instance sera à chaque fois qu’un bean sera référencé).
request portée d’un bean qui correspond à une requête HTTP (utilisable uniquement dans une contexte web compatible avec Spring MVC)
session portée d’un bean qui correspond à une session HTTP(utilisable uniquement dans une contexte web compatible avec Spring MVC)
global-session portée d’une definition d’un bean dans le contexte d’une portlet

a) Scope Singleton
Exemple d’un bean singleton

public class Client


{
private String message;

public Client() { message=””; }


public String getMessage() {return message; }
public void setMessage(String message) { this.message = message; }
}

22
Formation  : Développement JEE avec Spring

<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<bean id="clientBean" class="alti.formation.spring.Client" />
 
</beans>

package alti.formation.spring;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 

public class Test


{
public static void main( String[] args )
{
ApplicationContext contexte = new ClassPathXmlApplicationContext(new String[] {"contexte.xml"});
 
Client client1 = (Client) contexte.getBean("clientBean");
client1.setMessage("contenu client1");
System.out.println("Message de l’instance client1 : " + client1.getMessage());
 
//retrieve it again
Client client2 = (Client) contexte.getBean("clientBean");
System.out.println("Message de l’instance client2: " + client2.getMessage());
}
}

Résultat de l’exécution du code d’exemple :


Message de l’instance client1 : contenu client1
Message de l’instance client2 : contenu client1

Etant donné que le bean ‘clientBean’ est défini dans une portée de type singleton, la seconde référence pointera la même référence.

23
Formation  : Développement JEE avec Spring

b) Scope Prototype
Par opposition au scope singleton, le scope prototype va renvoyer une instance différente par appel.
Le fichier de définition du contexte d’application Spring sera :
<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<bean id="clientService" class="alti.formation.spring.ClientService" scope="prototype"/>
 
</beans>

L’exécution de l’exemple précédent avec la nouvelle définition du contexte d’application Spring donnera alors:
Message de l’instance client1 : contenu client1
Message de l’instance client2 : null

c) Utilisation de l’annotation scope


A partir des dernières versions de Spring (2.5.x) , il est possible d’utiliser une annotation pour spécifier la porte d’un bean Spring.

Code source Java de l’exemple

package alti.formation.spring.ClientService;
 
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
 
@Service
@Scope("prototype")
public class ClientService
{
String message;
 
public String getMessage() {
return message;
24
Formation  : Développement JEE avec Spring

}
 
public void setMessage(String message) {
this.message = message;
}
}

Il faut ensuite modifier l’application contexte de Spring (fichier xml) de manière à y inclure le nom du package pour lequel les annotations seront traitées.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
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">
 
<context:component-scan base-package="alti.formation.spring" />
 
</beans>

1.6.11 Les espaces de nommage


Le but de ces espaces de nommage est de simplifier la définition du contexte. Spring 2.0 propose plusieurs espaces de nommage (namespaces) : aop, jee, lang, tx et util.
Spring 2.5 ajoute les espaces de nommage context et jms. Spring définit aussi plusieurs autres espaces de nommages pour des usages plus particuliers : oxm, sws, ...
Pour ces propres besoins, il est aussi possible de définir ces propres espaces de nommage.
L'espace de nommage beans est obligatoire et est utilisé comme espace de nommage par défaut dans le fichier de configuration.
L'uri du schéma correspondant est www.springframework.org/schema/beans
Le schéma est défini dans le fichier xsd www.springframework.org/schema/beans/spring-beans-x.x.xsd
Exemple d’un fichier application context qui référence des xsd

<?xml version="1.0" encoding="UTF-8"?>


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="

25
Formation  : Développement JEE avec Spring

http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
 
<!-- ... -->
</beans>

Le tag <beans> est l'élément racine du fichier de configuration du context Spring. Le tag <beans> peut avoir plusieurs tags fils : <alias>, <bean>, <description> et <import>.
Le tag <bean> permet de configurer un bean. Il possède plusieurs attributs :

Attribut Rôle

abstract Booléen qui précise si le bean est abstrait : la valeur true indique au conteneur de ne pas créer d'instance

autowire Permet de préciser comment le bean sera injecté : byType, byName, constructor, autodetect, none (pas d'autowiring)

autowire-candidate Booléen qui précise si l'instance du bean peut être utilisé lors de l'injection de dépendances

class Le nom pleinement qualifié de la classe du bean

dependency-check Préciser les dépendances qui seront valorisées par le conteneur : simple (pour les primitives), object (pour les objets), default, none, all

depends-on Préciser un bean qui devra être initialisé avant que le bean soit instancié

destroy-method Préciser une méthode qui sera invoquée lorsque le bean est déchargé du conteneur

factory-bean Préciser un bean dont la méthode précisée par l'attribut factory-method sera utilisée comme fabrique

factory-method Préciser une méthode statique du bean précisé par l'attribut factory-bean qui sera utilisée par le conteneur comme une fabrique

id Identifiant du bean

init-method Nom de la méthode d'initialisation qui sera invoquée une fois l'instance créée et les dépendances injectées

lazy-init Booléen qui indique si l'instance sera initialisée tardivement

name Nom du bean

parent Préciser un bean dont la configuration sera héritée par le bean


scope Permet de préciser la portée du bean : singleton par défaut, prototype, request, session

Le tag <bean> peut avoir plusieurs tags fils : <constructor-arg>, <description>,<lookup-method>,<meta>,<property> et <replaced-method>.
Le tag <constructor-arg> permet d'utiliser l'injection par constructeur : il permet de fournir une valeur ou une référence sur un bean géré par le conteneur
Le tag <lookup-method> permet d'utiliser l'injection par getter : le getter est remplacé par une autre implémentation qui retourne une instance particulière.

26
Formation  : Développement JEE avec Spring

Le tag <property> permet d'utiliser l'injection par setter pour fournir une valeur à une propriété. Cette valeur peut être une référence sur un autre bean géré par le conteneur.
Le tag <replaced-method> permet de remplacer les traitements d'une méthode du bean par une autre implémentation.
Le tag <alias> permet de définir un alias pour un bean.
Le tag <import> permet d'importer une autre partie de la définition du contexte de Spring. Ce tag est particulièrement utile pour définir le contexte dans plusieurs fichiers,
chacun contenant des définitions de beans par thème fonctionnel ou technique (services, transactions, accès aux données, ...)
Le tag <description> permet de fournir une description de la définition du contexte ou d'un bean.

1.6.12 Initialisation et destruction de beans


1.6.13 Injection dans les propriétés des beans
1.6.14 Référencer d’autres beans

1.6.15 La liaison automatique inter beans (Auto-wiring)


Avec le framework Spring, il est possible de lier des beans automatiquement en utilisant la fonctionnalité auto-wiring dans la balise <bean>.

Exemple :
<bean id="client" class="alti.formation.spring.Client" autowire="byName" />

Spring, cinq (5) modes d’auto-wiring sont supportés:


 no – par défaut pas d’auto wiring, il faut référencer un autre bean manuellement en utilisant l’attribut “ref”
 byName – L’auto wiring par nom de propriété. Si le nom du bean est égal au nom d’un propriété d’un autre bean, il y a liaison automatique (auto wiring)
 byType – La liaison s’effectue par le type de donnée de la propriété. Si le type de donné du bean est compatible celle d’une propriété d’un autre bean, la liaison est
faite.
 constructor – correspond au mode byType comme argument de constructeur
 autodetect – Si il existe un constructeur par défaut, le mode est utilisé “autowired by constructor”; sinon cela sera le mode “autowire by type”.

Exemples des différents modes de liaison inter beans :


Deux classes d’objets sont définies pour les besoins de l’illustration de l’auto wiring avec le framework Spring

27
Formation  : Développement JEE avec Spring

package alti.formation.spring;
 
public class Client
{
private Personne personne;
 
public Client(Personne personne) {
this.personne = personne;
}
 
public void setPersonne(Personne personne) {
this.personne = personne;
}
//...
}

28
Formation  : Développement JEE avec Spring

package alti.formation.spring;
 
public class Personne
{
//...
}

1. Mode sans liaison Auto-Wiring


Pour rappel, ce mode est celui utilisé par défault par Spring. Dans le fichier de définition du contexte d’application de Spring, il est nécessaire de lier la référence du bean par
l’attribute ‘ref’ :
<bean id="client" class="alti.spring.formation.Client">
<property name="person" ref="personne" />
</bean>
 
<bean id="personne" class="alti.formation.spring.Personne" />

2. Le mode de liaison par nom (Auto-Wiring ‘byName’)


Dans ce mode de liaison, le nom du bean correspond à celui de la propriété d’une dépendance. Dans l’exemple  ci-dessous, le bean client possède la propriété personne qui
correspond au bean personne :
<bean id="client" class="alti.formation.spring.Client" autowire="byName" />
 
<bean id="personne" class="alti.formation.spring.Personne" />

3. Le mode de liaison par type (Auto-Wiring ‘byType’)


Ce mode est similaire est précédent, sauf qu’il utilise le type de la propriété pour réaliser l’injection de la dépendance. Dans l’exemple suivant, comme le type de type du bean
personne est identique à celui de la propriété du bean client, Spring injecte la dépendance en utilisant la méthode d’écriture (setter) “setPersonne(Personne personne)“.
<bean id="client" class=" alti.formation.spring.Client" autowire="byType" />
 
<bean id="personne" class="alti.formation.spring.Personne" />

4. Le mode de liaison par constructeur (Auto-Wiring ‘constructor’)


La liaison (injection de dépedanc) est réalisé par le type de donnée de la propriété, donc la valeur est transmise dans le constructeur. Exemple:

<bean id="client" class="alti.formation.spring.Client" autowire="constructor" />

29
Formation  : Développement JEE avec Spring

 
<bean id="personne" class="alti.formation.spring.Personne" />

5. Auto-Wiring ‘autodetect’
Il existe le mode d’injection par auto-détection. Dans ce mode, s’il existe un constrcteur par défaut, il utilisera l’injection par contructeur, ou le mode par type.
Exemple d’un contexte d’application Spring qui utilise le mode auto détection :
<bean id="client" class="alti.spring.formation.Client" autowire="autodetect" />
 
<bean id="personne" class="alti.formation.spring.Personne"" />

2 Accès aux bases de donnés


Le framework Spring a prévu plusieurs méthodes pour accèder à une base de données. Nous allons dérouler un exemple permettant d’accèder à une base de données
relationnelles MySQL.

2.1 Accès par JDBC


a) Définition

Pour les besoins de l’exemple, nous créons la table Client suivante:

create database gestion;

use gestion;

CREATE TABLE `client` (


`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`nom` VARCHAR(100) NOT NULL,
`age` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

b) Dépendances du projet
30
Formation  : Développement JEE avec Spring

Nous rajotons les dependences Maven suivantes au fichier pom.xml :

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mkyong.common</groupId>
<artifactId>SpringExample</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpringExample</name>
<url>http://maven.apache.org</url>
 
<dependencies>
 
<!-- Spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
 
<!-- MySQL database driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
 
</dependencies>
</project>

c) Classe du modèle
package alti.formation.spring.modele;
 
import java.sql.Timestamp;
 
public class Client
31
Formation  : Développement JEE avec Spring

{
private int id;
private String nom;
private int age;
// rajouter les méthodes getter et setter
}

d) Définition de l’interface du Data Access Object (DAO)

package alti.formation.spring.dao;
 
import alti.formation.spring.modele.Client;
 
public interface ClientDAO
{
public void inserer(Client client);
public Customer chercherParId(int id);
}

L’implémentation du DAO est donnée par la classe suivante

32
Formation  : Développement JEE avec Spring

package alti.formation.spring.dao;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import alti.formation.spring.dao.ClientDAO;
import alti.formation.spring.modele.Client;
 
public class JdbcClientDAO implements ClientDAO
{
private DataSource dataSource;
 
public void setDataSource(DataSource dataSource)
{
this.dataSource = dataSource;
}
 
public void inserer(Client client){
 
String sql = "INSERT INTO CLIENT " +
"(ID, NAME, AGE) VALUES (?, ?, ?)";
Connection cnt = null;
 
try {
cnt = dataSource.getConnection();
PreparedStatement ps = cnt.prepareStatement(sql);
ps.setInt(1, client.getId());
ps.setString(2, client.getNom());
ps.setInt(3, client.getAge());
ps.executeUpdate();
ps.close();
 
}
catch (SQLException e)
{
throw new RuntimeException(e);
 

33
Formation  : Développement JEE avec Spring

}
finally
{
if (cnt != null) {
try {
cnt.close();
} catch (SQLException e) {}
}
}
}
 
public Customer chercherClientParId(int id)
{
  String sql = "SELECT * FROM client WHERE ID = ?";
 
Connection cnt = null;
 
try {
cnt = dataSource.getConnection();
PreparedStatement ps = cnt.prepareStatement(sql);
ps.setInt(1, id);
Customer customer = null;
ResultSet rs = ps.executeQuery();
if (rs.next())
{
client = new Client(
rs.getInt("ID"),
rs.getString("NOM"),
rs.getInt("AGE")
);
}
rs.close();
ps.close();
return client;
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (cnt != null) {
try {

34
Formation  : Développement JEE avec Spring

cnt.close();
} catch (SQLException e) {}
}
}
}
}

e) Configuration Spring du bean


Trois fichiers de configuration de Spring seront créés:
Client.xml
<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<bean id="clientDAO" class="com.mkyong.customer.dao.impl.JdbcCustomerDAO">
<property name="dataSource" ref="dataSource" />
</bean>
 
</beans>

Le fichier datasource.xml

<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
 
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/formation" />
<property name="username" value="root" />
<property name="password" value="password" />
</bean>
 
</beans>
35
Formation  : Développement JEE avec Spring

Le fichier : applicationContexte.xml

<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<import resource="datasource.xml" />
<import resource="client.xml" />
 
</beans>

Exécution du code de test :

package alti.formation.spring;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import alti.formation.spring.dao.ClientDAO
import alti.formation.spring.modele.Client;
 
public class App
{
public static void main( String[] args )
{
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContexte.xml");
 
ClientDAO clientDAO = (ClientDAO) context.getBean("clientDAO");
Client client = new Client(1, "test", 40);
clientDAO.inserer(client);
 
Client existant = clientDAO.chercherParId(1);
System.out.println(existant);
 
}
}

36
Formation  : Développement JEE avec Spring

2.2 Accès par JdbcTemplate


Avec le framework Spring, il est possible de simplifier le développement JDBC en utilisant les classes JdbcTemplate et JdbcDaoSupport.
La classe JdbcTemplate permet de générer le code redondant dans un DAO.
Exemple :
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
 
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
 
public void insert(Customer customer)
{
  String sql = "INSERT INTO CLIENT(ID, NOM, AGE) VALUES (?, ?, ?)";
jdbcTemplate = new JdbcTemplate(dataSource);
 
jdbcTemplate.update(sql, new Object[] { client.getId(), client.getNom(),client.getAge() });
 
}

a) Intégration de JdbcDaoSuppor

En dérivant de la classe JdbcDaoSupport, il n’est plus nécessaire de renseigner la datasource et l’instance JdbcTemplate dans la classe DAOà développer. .

public class ClientDAO extends JdbcDaoSupport implements ClientDAO


{
//no need to set datasource here
public void insert(Customer customer){
 
String sql = "INSERT INTO CLIENT (ID, NAME, AGE) VALUES (?, ?, ?)";
 
getJdbcTemplate().update(sql, new Object[] { client.geId(), client.getNom(),client.getAge()
});
 
}

37
Formation  : Développement JEE avec Spring

Fichier dataSource.xml

<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
 
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/formation" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
 
</beans>

Fichier applicationContext :

<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<bean id="customerDAO" class="alti.formation.spring.dao.ClientDAO">
<property name="dataSource" ref="dataSource" />
</bean>
 
</beans>

2.3 Intégration de Spring avec Hibernate


L’implémentation du framework Spring a prévu une intégration avec l’ORM Hibernate. Voici un exemple type d’intégration Spring/Hibernate :

Fichier applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
38
Formation  : Développement JEE avec Spring

xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>properties/database.properties</value>
</property>
</bean>
 
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
 
<!-- Configuration de la session factory d’Hibernate -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
 
<property name="dataSource">
<ref bean="dataSource"/>
</property>
 
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
 
<property name="annotatedClasses">
<list>
<value>alti.formation.spring.modele.EcritureComptable </value>
</list>
</property>
 

39
Formation  : Développement JEE avec Spring

</bean>

</beans>

Le code Java d’exécution illustre l’intégration de Spring et d’Hibernate:


package alti.formation.spring;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
import alti.formation.spring.EcritureComptable;
import alti.formation.spring.EcritureService;

 
public class App
{
public static void main( String[] args )
{
ApplicationContext appContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
 
EcritureService ecritureService = (EcritureService) appContext.getBean("ecritureBean");
 
/** insert **/
Ecriture ecriture = new Ecriture();
ecriture.setCompte("123");
ecritureService.save(ecriture);
 
/** recherche **/
Piece piece = ecritureService.chercherPieceParNumero("P0112");
System.out.println(piece);
 
/** mise à jour **/
piece.setPeriode("2012-12");
ecritureService.miseAJour(piece);
 
/** suppression **/
ecritureService.supprimer(piece);

40
Formation  : Développement JEE avec Spring

 
System.out.println("Fait");
}
}

2.4

41
Formation  : Développement JEE avec Spring

3 Gestion des transactions

Java Transaction (JTA) est une API présente dans la spécification J2EE.
JTA fournit des interfaces Java standards entre un gestionnaire de transaction et les différentes parties impliquées dans un système de transactions distribuées  : le gestionnaire
de ressources, le serveur d'application et les applications transactionnelles.
JTA est un protocole de commit à deux phases :
1. 1re phase : Chaque partie prenant part à la transaction distribuée s'engage à verrouiller les données concernées et à valider ces données une fois la transaction terminée
2. 2e phase : Chaque partie valide les changements des données. Cette phase est obligatoire, dès lors que les parties se sont engagées.
Ce protocole de commit à deux phases fonctionne plutôt bien sur les transactions courtes, mais est totalement inefficace en cas de transaction lente où le risque d'une
déconnexion ou bien d'un crash entre les deux phases est élevé, car les verrous restent posés après la première phase et ne sont libérés qu'après la deuxième phase.

Le choix d'un gestionnaire de transactions distribuées est souvent délicat. Généralement pour les applis Web on utilise directement le gestionnaire de transaction du serveur
d'application. Par contre dans le cas d'une application standalone (ou batch) ou d'un mécontentement par rapport au gestionnaire de votre serveur, il faut avoir recours à un
gestionnaire de transactions indépendant. J'ai pu trouver 6 implémentations majeures, que j'ai évalué assez sommairement (mais efficacement je l'espère).
Dans cet article je présenterai les options qui s'offrent à vous, ainsi qu'un exemple de configuration et d'implémentation de transactions distribuées avec Atomikos.
Le cas d'utilisation est une transaction entre un broker JMS, et 2 bases de données. Le broker JMS est ActiveMQ, et les bases données testées sont Oracle et MySQL.

3.1 Tour d'horizon des gestionnaires de transactions indépendants


 Atomikos
 Il me semble être le plus populaire et le plus actif. Il gère plusieurs types de ressources et semble mature (plus de 6ans). Dans sa version gratuite JDBC et JMS, et dans
la version commerciale JMX,SOAP et RMI-IIOP viennent en plus.
 BTM (Bitronix transaction manager)
Assez populaire, mais semble plus en retrait par rapport à Atomikos. Il gère du JDBC,JMS et JMX
 JOTM
Le projet était à l'abandon, et il y a eu une reprise récente. Il gère le JDBC,JMS et RMI. La documentation semble légère.
 JBoss Transaction
J'avais arrêté assez rapidement mon évaluation de ce produit, car il ne s'intégrait pas avec Spring (ce qui était important dans le cadre des projets que je gérais)
 Jencks
La dernière release date de 2007…

42
Formation  : Développement JEE avec Spring

 Gestionnaire de transaction de Geronimo


Non évalué

3.2 Implémentation d'un scénario "Two phase-commit" avec Atomikos


Le cas choisi est la gestion d'une transaction entre 2 ressources distribuées. Le 1er test se déroule avec succès. Une exception est lancé dans le 2ème test entre les 2 transactions
unitaires afin qu'il y ait un rollback de la transaction globale.
Dans le 1er exemple les 2 ressources distribués sont 2 bases de données distinctes (une base Oracle et une base MySQL).
Le 2ème exemple utilise une base de données Oracle et un broker JMS (Active MQ).

Le contenu fichier pom.xml du projet :

a) Fichier pom.xml (intégration Maven)

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"


xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelversion>4.0.0</modelversion>
 
<groupid>alti.formation.spring</groupid>
<artifactid>jta</artifactid>
<packaging>jar</packaging>
<name>xa-spring</name>
<description>Exemple d’implémentation du commit à deux phases avec l’implémentation Atomikos de JTA et Sppring</description>
<version>1.0-SNAPSHOT</version>
<inceptionyear>2009</inceptionyear>

<build>
<pluginmanagement>
<plugins>
<plugin>
<artifactid>maven-eclipse-plugin</artifactid>
<configuration>
<wtpversion>1.5</wtpversion>
<wtpcontextname>blank-app</wtpcontextname>
<springcontext>

43
Formation  : Développement JEE avec Spring

<include>${basedir}/src/main/resources/spring/*.xml</include>
</springcontext>
</configuration>
</plugin>
</plugins>

</pluginmanagement>
</build>
 
<dependencies>
 
<!-- JTA implementation -->
<dependency>
<groupid>com.atomikos</groupid>
<artifactid>transactions-essentials-all</artifactid>
<version>3.5.9</version>
<exclusions>
<exclusion>
<groupid>org.hibernate</groupid>
<artifactid>hibernate</artifactid>
</exclusion>
</exclusions>
</dependency>
 
<!-- To run as a standalone application (without server) -->
<dependency>
<groupid>tomcat</groupid>
<artifactid>naming-factory</artifactid>
<version>5.5.23</version>
</dependency>
 
<dependency>
<groupid>tomcat</groupid>
<artifactid>naming-resources</artifactid>
<version>5.5.23</version>
</dependency>
 
<!-- Active MQ(broker JMS) -->
<dependency>

44
Formation  : Développement JEE avec Spring

<groupid>org.apache.activemq</groupid>
<artifactid>activemq-core</artifactid>
<version>5.2.0</version>
</dependency>
 
<!-- For tests -->
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>4.4</version>
<scope>test</scope>
</dependency>

<dependency>
<groupid>org.unitils</groupid>
<artifactid>unitils</artifactid>
<version>2.0</version>
<scope>test</scope>
</dependency>
 
<!-- Spring -->
<dependency>
<groupid>log4j</groupid>
<artifactid>log4j</artifactid>
<version>1.2.12</version>
</dependency>

<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring</artifactid>
<version>2.5.5</version>
</dependency>

<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-aspects</artifactid>
<version>2.5.5</version>
<exclusions>
<exclusion>

45
Formation  : Développement JEE avec Spring

<groupid>org.springframework</groupid>
<artifactid>spring-core</artifactid>
</exclusion>
<exclusion>
<groupid>org.springframework</groupid>
<artifactid>spring-beans</artifactid>
</exclusion>
</exclusions>
</dependency>
 
<!-- PERSISTANCE -->
<dependency>
<groupid>hsqldb</groupid>
<artifactid>hsqldb</artifactid>
<version>1.8.0.7</version>
</dependency>

<dependency>
<groupid>org.hibernate</groupid>
<!--         <artifactId>hibernate-core</artifactId>-->
<!--         <version>3.3.2.GA</version>-->
<artifactid>hibernate</artifactid>
<version>3.2.7.ga</version>
</dependency>

<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-annotations</artifactid>
<version>3.4.0.GA</version>
</dependency>

<!-- Implementation of sl4j required by hibernate-annotations -->


<dependency>
<groupid>org.slf4j</groupid>
<artifactid>slf4j-jdk14</artifactid>
<version>1.4.2</version>
</dependency>

<dependency>

46
Formation  : Développement JEE avec Spring

<groupid>commons-dbcp</groupid>
<artifactid>commons-dbcp</artifactid>
<version>1.2.2</version>
</dependency>
 
<!-- JDBC Driver -->
<dependency>
<groupid>mysql</groupid>
<artifactid>mysql-connector-java</artifactid>
<version>5.1.8</version>
</dependency>

<dependency>
<groupid>com.oracle</groupid>
<artifactid>ojdbc14</artifactid>
<version>10.2.0.2.0</version>
</dependency>
 
</dependencies>
 
</project>

b) Configuration et codage de l'application

Dans le dossier "resources" pour les utilisateurs de Maven ou dans le classpath, doivent être présent les fichiers jndi.properties et transactions.properties.

Le contenu de jndi.properties est le suivant:

java.naming.factory.initial=  
org.apache.naming.java.javaU
RLContextFactory Les propriétés nécessaires (présentes dans le fichier) transaction.properties sont les suivantes:

#Factory implementation
47
Formation  : Développement JEE avec Spring

class of the transaction


core (REQUIRED)
com.atomikos.icatch.service=
com.atomikos.icatch.standalo
ne.UserTransactionServiceFac
tory
       
#Set output directory where
console file and other files
are to be put
com.atomikos.icatch.output_d
ir = C:\\logs

#Set directory of log files;


make sure this directory
exists!
com.atomikos.icatch.log_base
_dir = C:\\logs

#If you want to do explicit


resource registration or not
com.atomikos.icatch.automati
c_resource_registration=true 

   
#Granularity of output to
the console file
com.atomikos.icatch.console_
log_level=DEBUG

#Set the max timeout (in


milliseconds) for local
transactions
com.atomikos.icatch.max_time
out = 60000

#The global unique name of


this transaction manager

48
Formation  : Développement JEE avec Spring

process
com.atomikos.icatch.tm_uniqu
e_name = xa-Spring

Les fichiers Spring à configurer sont multiples car j'ai préféré éclater la configuration. Le fichier Spring chapeau référence un fichier pour la configuration des transactions, deux
autres fichiers pour la configuration respective des bases de données, et un dernier pour le broker JMS.
Commençons par un des fichiers pour la base de données. Je ne présenterai qu'un seul car la configuration est à peu près similaire, mais toutes les informations sur la
configuration des différents type de bases sont présentes (base de données non compatible XA come HsqlDB, base Oracle et Mysql).
NB: Il est important de noter que pour chaque base il faudra associer un sessionFactory différent.
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd">
 
<!-- ==DATABASE SELECTION (use of an XA or a no XA datasource)== -->
<!-- NB: Remember to change the Hibernate dialect -->
 
<!-- No XA datasource (if you haven't got a XA compatible database) -->
<!-- <bean id="dataSourceDb1"-->
<!--     class="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean"-->
<!--     destroy-method="close">-->
<!--     <property name="uniqueResourceName" value="Database1"/>-->
<!--     <property name="user" value="SA"/>-->
<!--     <property name="password" value="" />-->
<!--     <property name="url" value="jdbc:hsqldb:mem:base1"/>-->
<!--     <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>-->
<!--     <property name="poolSize" value="1"/>-->

49
Formation  : Développement JEE avec Spring

<!--     <property name="borrowConnectionTimeout" value="60"/>-->


<!-- </bean>-->
 
<!-- XA datasource MySQL-->
<!-- <bean id="dataSourceDb1" class="com.atomikos.jdbc.AtomikosDataSourceBean"-->
<!--     init-method="init" destroy-method="close">-->
<!--     <property name="uniqueResourceName" value="Database1"/>-->
<!--     <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>-->
<!--     <property name="xaProperties">-->
<!--         <props>-->
<!--             <prop key="databaseName">xaDB1</prop>-->
<!--             <prop key="serverName">localhost</prop>-->
<!--             <prop key="port">3306</prop>-->
<!--             <prop key="user">root</prop>-->
<!--             <prop key="password"></prop>-->
<!--             <prop key="url">jdbc:mysql://localhost:3306/xaDB1</prop>-->
<!--         </props>-->
<!--     </property>-->
<!-- </bean>-->
 
<!-- XA datasource Oracle 10-->
<bean id="dataSourceDb1" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="Database1"/>
<property name="xaDataSourceClassName" value="oracle.jdbc.xa.client.OracleXADataSource"/>
<property name="xaProperties">
<props>
<prop key="user">demo</prop>
<prop key="password">demo</prop>
<prop key="URL">jdbc:oracle:thin:@184.11.192.56:1521:XE</prop>
</props>
</property>
</bean>
 
<!--  Hibernate Session Factory : by annotation-->
<bean id="sessionFactoryDb1" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSourceDb1" />
<property name="annotatedClasses">
<list>

50
Formation  : Développement JEE avec Spring

<value>com.onx.sample.xa.model.Person</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<!--             <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>-->
<!--             <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>-->
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.jdbc.batch_size">20</prop>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.connection.release_mode">auto</prop>
<prop key="hibernate.show_sql">true</prop>
 
<!-- JTA properties -->
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.factory_class">com.atomikos.icatch.jta.hibernate3.AtomikosJTATransactionFactory</prop>
<prop
key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>
 
</props>
</property>
</bean>
 
</beans>

Le schéma reste classique pour la partie Java avec des couches "Service", "Model" et "DAO". Le model choisi est une classe "Person" avec 6 attributs (id, name, firstname, byte[]
data, accountBalance, age). Au niveau DAO une classe GenericDAO étend HibernateDAOSupport afin de faciliter l'utilisation du HibernateTemplate. Voici un exemple de
l'implémentation de la DAO pour la sessionFactory2 (rappel: une session factory par base):

@Repository("PersonDAOForDB2")
public class PersonDAOForDB2Impl extends GenericDaoHibernateImpl<Person, Long> implements GenericDao<Person, Long>, PersonDAOForDB2
{
 
@Autowired
public PersonDAOForDB2Impl(@Qualifier("sessionFactoryDb2")SessionFactory sessionFactory) {

51
Formation  : Développement JEE avec Spring

super(Person.class);
setSessionFactory(sessionFactory);
}
}

On reste dans une utilisation classique. Au niveau du service qui sera appelé on a le code suivant:
@Service("personService")
public class PersonServiceImpl implements PersonService {
 
/** DAO of database 1 **/
@Autowired
private PersonDAOForDB1 personDaoDb1;
/** DAO of database 2 **/

@Autowired
private PersonDAOForDB2 personDaoDb2;
 
public Person getPersonByIdForDB1(Long id) {
return personDaoDb1.get(id);
}
 
public Person getPersonByIdForDB2(Long id) {
return personDaoDb2.get(id);
}
 
/**
* @param personDaoDb1 the personDaoDb1 to set
*/
public void setPersonDaoDb1(PersonDAOForDB1 personDaoDb1) {
this.personDaoDb1 = personDaoDb1;
}
 
/**
* @param personDaoDb2 the personDaoDb2 to set
*/
public void setPersonDaoDb2(PersonDAOForDB2 personDaoDb2) {

52
Formation  : Développement JEE avec Spring

this.personDaoDb2 = personDaoDb2;
}
 
}

La configuration JMS établie comprend la définition des fabriques de connections pour les transactions XA. Une queue sera utilisée pour cet exemple.
La configuration est commentée. La compréhension me semble facile. Si vous avez des difficultés il faudra se référer à la documentation sur Spring JMS.

<?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:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-2.5.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
<!-- ##XA Connection Factory knowing how to connect to the JMS broker -->
<bean id="xaJmsConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<!-- URL for a real Active MQ -->
<!--     <property name="brokerURL" value="tcp://localhost:61616" />-->
<!-- URL for an embedded Active MQ (no need to download and install it) -->
<property name="brokerURL" value="vm://embedded?broker.persistent=false" />
</bean>
 
<bean id="queueConnectionFactoryBean" class="com.atomikos.jms.QueueConnectionFactoryBean" init-method="init">
<property name="resourceName" value="Execution_Q"/>
<property name="xaQueueConnectionFactory" ref="xaJmsConnectionFactory"/>
</bean>
 
<!-- ##Message destination -->
<!-- A queue (for point-to-point mode) -->
<bean id="onxQueueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="onx/jms/queue" />
</bean>
 
<!--
##JMS Template (used to avoid verbose of connection management etc.)
-->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">

53
Formation  : Développement JEE avec Spring

<property name="connectionFactory" ref="queueConnectionFactoryBean" />


 
<!-- Possibility to define a default destination -->
<!-- Then no need to declare it again in bean using jmsTemplate -->
<property name="defaultDestination" ref="onxQueueDestination" />
 
<!-- TimeOut to receive message -->
<property name="receiveTimeout" value="4000" />
 
<!-- Transaction mode when creating a JMS session -->
<property name="sessionTransacted" value="true"/>
</bean>
 
</beans>

Maintenant il nous reste à configurer la gestion des transaction avec Spring et Atomikos, puis écrire les classes de test. Commençons par la gestion des transactions.
<?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: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/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
 
<!--UserTransactionManager to manage transactions and set properties-->
<bean id="userTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
 
<!--Indicate when close is called, if we should force transactions to terminate-->
<property name="forceShutdown" value="false" />
</bean>
 
<!-- UserTransaction (allow to manage transactions explicitly) -->
<bean id="userTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
 
<!--Configure the Spring framework to use JTA transactions from Atomikos-->
<bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
54
Formation  : Développement JEE avec Spring

<property name="transactionManager" ref="userTransactionManager" />


<property name="userTransaction" ref="userTransaction" />
</bean>
 
<!-- Indicate we're using Spring annotation -->
<tx:annotation-driven transaction-manager="jtaTransactionManager" />
 
</beans>

Les tests
Je me suis appuyé sur Unitils afin de développer les classes de tests. Et je me suis retrouvé confronté à des erreurs sur les transactions. En passant par des Main java, je n'avais
aucun souci. La petite astuce est de penser à désactiver la gestion des transactions d'Unitils qui est activé par défaut.
Maintenant que vous êtes avertis, passons à l'implémentation des scénarios.

Classe de Services

La classes de service qui sera finalement appelée est la suivante (la classe personService était utilie pour des petits tests sur les DAO).

**
* <code>XaTransactions</code> does distributed transactions with
* different databases and JMS broker.
*
* @author Fabrice LUCIEN <a href="mailto:flucien@on-x.com"/>
*/
@Service("xaTransactions")
public class XaTransactionsImpl implements XaTransactions {
 
/** Logger **/
private Logger logger=Logger.getLogger(this.getClass());
 
/** DAO of database 1 **/
@Autowired
private PersonDAOForDB1 personDaoDb1;
/** DAO of database 2 **/
@Autowired
private PersonDAOForDB2 personDaoDb2;

55
Formation  : Développement JEE avec Spring

/** JMS consumer **/


@Autowired
private Consumer consumer;
/** last ID inserted**/
private Long lastPersonIdForDB1=null,lastPersonIdForDB2=null;
 
/*
* (non-Javadoc)
* @see com.onx.sample.xa.service.XaTransactions#twoDatabase(boolean)
*/
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void twoDatabase(boolean throwException) {
Person person = new Person();
person.setFirstname("Bargminthon");
person.setName("Jean");
 
lastPersonIdForDB1=personDaoDb1.save(person);
logger.info("Save in DB1 is OK and waits the end of the transaction.");
lastPersonIdForDB2=personDaoDb2.save(person);
logger.info("Save in DB2 is OK and waits the end of the transaction.");
 
if(throwException) {
logger.info("Simulation of an error during transaction. We throw a NullPointer exception");
throw new NullPointerException();
}
}
 
/*
* (non-Javadoc)
* @see com.onx.sample.xa.service.XaTransactions#consumeJmsMsgAndUpdateDB(boolean)
*/
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void consumeJmsMsgAndUpdateDB(boolean throwException) {
 
//Consume the message
logger.info("Trying to get a message on the queue");
Person person=consumer.receive();
 
if(person==null) {

56
Formation  : Développement JEE avec Spring

logger.info("We didn't get any message. Timeout has probably been reached...");
return;
}

//Update the database


lastPersonIdForDB1=personDaoDb1.save(person);
logger.info("Save in DB1 is OK and waits the end of the transaction.");
 
if(throwException) {
logger.info("Simulation of an error during transaction. We throw a NullPointer exception");
throw new NullPointerException();
}
}
 
/*
* (non-Javadoc)
* @see com.onx.sample.xa.service.XaTransactions#getLastPersonIdForDB1()
*/
public Long getLastPersonIdForDB1() {
return lastPersonIdForDB1;
}
 
/*
* (non-Javadoc)
* @see com.onx.sample.xa.service.XaTransactions#getLastPersonIdForDB2()
*/
public Long getLastPersonIdForDB2() {
return lastPersonIdForDB2;
}
 
}

Transactions entre 2 bases de données


/**
* <code>TwoDatabases</code> tries to do a two phase commit on two databases.
* In the test 'twoDatabasesCommit' the transaction finish well with persisted data.
57
Formation  : Développement JEE avec Spring

* In the test 'twoDatabasesRollback' the rollback should work for these two databases.
*
* @author Fabrice LUCIEN <a href="mailto:flucien@on-x.com"/>
*/

@RunWith(UnitilsJUnit4TestClassRunner.class)
//Avoid that Unitils manage the begin and the end of the transaction
@Transactional(TransactionMode.DISABLED)
@SpringApplicationContext( { "classpath:/spring/spring.xml" })
public class TwoDatabases {
 
/** Logger **/
private Logger logger=Logger.getLogger(this.getClass());
 
/** XA services **/
@SpringBeanByType
private XaTransactions xaTransactions;
 
/** Person services **/
@SpringBeanByType
private PersonService personService;
 
@Test
public void twoDatabasesCommit() {
xaTransactions.twoDatabase(false);
 
Long personIdInsertedInDB1 = xaTransactions.getLastPersonIdForDB1();
Long personIdInsertedInDB2 = xaTransactions.getLastPersonIdForDB2();
 
Assert.assertNotNull(personIdInsertedInDB1);
Assert.assertNotNull(personIdInsertedInDB2);
 
Assert.assertNotNull(personService.getPersonByIdForDB1(personIdInsertedInDB1));
Assert.assertNotNull(personService.getPersonByIdForDB2(personIdInsertedInDB2));
}
 
@Test

58
Formation  : Développement JEE avec Spring

public void twoDatabasesRollback() {


 
try {
xaTransactions.twoDatabase(true);   //An exception is throw
} catch (NullPointerException e) {
logger.info("Transaction failed as expected");
}
 
Long personIdInsertedInDB1 = xaTransactions.getLastPersonIdForDB1();
Long personIdInsertedInDB2 = xaTransactions.getLastPersonIdForDB2();
 
Person personForDB1=personService.getPersonByIdForDB1(personIdInsertedInDB1);
Person personForDB2=personService.getPersonByIdForDB2(personIdInsertedInDB2);
 
Assert.assertNull(personForDB1);
Assert.assertNull(personForDB2);
 
}
60. 
61.}

Transaction entre 1 base de données et un broker JMS


/**
* <code>JmsWithDatabase</code> tries to do a two phase commit with a JMS broker and a database.
* In the test 'jmsAndDBCommit' the transaction finish well with persisted data and the message is consumed.
* In the test 'jmsAndDBRollback' the rollback should work for the database and the JMS broker.
*
*/
@RunWith(UnitilsJUnit4TestClassRunner.class)
@Transactional(TransactionMode.DISABLED)
@SpringApplicationContext( {"classpath:/spring/spring.xml"})
public class JmsWithDatabase {
 
/** Logger **/
private Logger logger=Logger.getLogger(this.getClass());
59
Formation  : Développement JEE avec Spring

 
/** XA services **/
@SpringBeanByType
private XaTransactions xaTransactions;
 
/** Person services **/
@SpringBeanByType
private PersonService personService;
 
/** Producers **/
@SpringBeanByType
private Producer producer;
 
/** bean to send **/
private Person person;
 
@Before
public void initData() {
person = new Person();
person.setFirstname("Mickeal");
person.setName("Jackson");
}
 
@Test
public void jmsAndDBCommit() {
//Sends the message
producer.sendPersonInfo(person);
logger.info("A message was sent on the queue");
 
//Gets the message and updates the DB in one transaction
xaTransactions.consumeJmsMsgAndUpdateDB(false);
 
//Check if the DB has been updated
Long personIdInsertedInDB1 = xaTransactions.getLastPersonIdForDB1();
Person personForDB1=personService.getPersonByIdForDB1(personIdInsertedInDB1);
Assert.assertEquals(person.getFirstname(),personForDB1.getFirstname());
 
//TODO check the message was consumed instead looking the monitor pages
}

60
Formation  : Développement JEE avec Spring

 
@Test
public void jmsAndDBRollback() {
//Sends the message
producer.sendPersonInfo(person);
logger.info("A message was sent on the queue");
 
//Gets the message and updates the DB in one transaction
try {
xaTransactions.consumeJmsMsgAndUpdateDB(true);//An exception is throw
} catch (NullPointerException e) {
logger.info("Transaction failed as expected");
}
 
//Check if the DB has been updated
Long personIdInsertedInDB1 = xaTransactions.getLastPersonIdForDB1();
Person personForDB1=personService.getPersonByIdForDB1(personIdInsertedInDB1);
Assert.assertNull(personForDB1);
 
//TODO check the message was not consumed instead looking the monitor pages
}
}

61
Formation  : Développement JEE avec Spring

Spring permet une gestion et une propagation des transactions. Depuis Spring 2.0, les transactions sont mises en oeuvre en utilisant l'AOP.
Généralement, c'est la couche service qui assure la gestion des transactions des traitements. La déclaration des méthodes qui doivent être transactionnelles peut se faire par
déclaration dans la configuration de Spring ou par des annotations.
L'utilisation des transactions peut se faire par déclaration ou par programmation en utilisant une API dédiée. L'utilisation des transactions de manière déclarative est la façon la
plus simple de les mettre en oeuvre car c'est celle qui limite les impacts dans le code de l'application.
La déclaration du comportement transactionnel se fait au niveau des méthodes de toutes les classes concernées. Cependant, Spring n'est pas en mesure de propager un contexte
transactionnel dans des appels de méthodes distantes.
Depuis Spring 2.0, il n'est plus nécessaire de déclarer un bean de type TransactionProxyFactoryBean mais il faut utiliser les tags de l'espace de nommage tx.
La mise en oeuvre des transactions avec Spring se fait essentiellement de manière déclarative : la façon la plus simple d'utiliser une transaction avec Spring est d'ajouter la
déclaration de l'espace de nommage tx et le tag <tx:annotation-driven/> dans le fichier de configuration et d'utiliser le tag @Transaction sur les classes et/ou les méthodes
concernées.

 3.1 La gestion des transactions par Spring


La mise en oeuvre des transactions repose sur une abstraction qui permet de les mettre en oeuvre de façon similaire quelle que soit l'implémentation de la gestion des
transactions sous-jacente utilisée (transactions globales avec JTA ou transactions locales avec JDBC, JPA, JDO, Hibernate, ...).
Un gestionnaire de transactions doit implémenter l'interface org.springframework.transaction.PlatformTransactionManager.
Spring propose plusieurs gestionnaires de transactions notamment :
 org.springframework.orm.hibernate3.HibernateTransactionManager : pour utiliser Hibernate
 org.springframework.transaction.jta.JtaTransactionManager : pour utiliser une implémentation de JTA fournie par un serveur d'applications
 org.springframework.jdbc.datasource.DataSourceTransactionManager : pour utiliser une datasource avec JDBC
L'utilisation des transactions est ainsi identique quelque soit la solution utilisée : seule la déclaration d'un gestionnaire de transactions est à faire et c'est lui qui va se charger de
gérer les transactions de manière spécifique à la solution utilisée.
Une transaction gérée par Spring possède plusieurs caractéristiques :
 isolation : permet de préciser le niveau d'isolation de la transaction par rapport aux autres transactions.
 propagation : permet de préciser comment les traitements s'intègrent dans un contexte transactionnel
 timout : le temps maximum durant lequel la transaction peut s'exécuter. Au delà de ce temps, 1a transaction est annulée (rollback).
 read only : permet de préciser si les données sont lues uniquement ou si elles peuvent être mises à jour ceci à fin de permettre certaines optimisations

3.2 La propagation des transactions

62
Formation  : Développement JEE avec Spring

Une transaction peut être logique ou physique. Une transaction logique est gérée par Spring : une ou plusieurs transactions logiques permettent à Spring de déterminer le statut
de la transaction physique.
La propagation PROPAGATION_REQUIRED créée une transaction logique pour chaque méthode dont le contexte transactionnel possède ce type de propagation. Durant la portée de
cette transaction logique, celle-ci peut être validée ou annulée.
Comme les transactions logiques peuvent être imbriquées, pour indiquer à une transaction englobante qu'une transaction sous-jacente a été annulée, une exception de type
UnexpectedRollbackException est levée.
La propagation PROPAGATION_REQUIRES_NEW créé une nouvelle transaction indépendante pour chaque méthode dont le contexte transactionnel possède ce type de propagation.
Chaque contexte transactionnel dispose de sa propre transaction physique. Le rollback de la transaction n'a aucune incidence sur le rollback d'une transaction englobante.
La propagation PROPAGATION_NESTED utilise une seule transaction physique avec des savepoints. Il est donc possible de faire un rollback dans le contexte transactionnel jusqu'au
précédent savepoint sans annuler l'intégralité de la transaction physique sous-jacente qui poursuit son exécution. Le gestionnaire de transaction doit permettre un support des
savepoints ce qui pour le moment n'est possible qu'avec le DataSourceTransactionManager qui utilise les transactions JDBC.

3.3 L'utilisation des transactions de manière déclarative


Historiquement, l'utilisation des transactions avec Spring se faisait de manière déclarative dans le fichier de configuration XML. Cette déclaration pouvait devenir fastidieuse et
source d'erreur car relativement compliquée et lourde en fonction de la taille de l'application. La possibilité de déclarer les transactions avec des annotations à grandement
simplifié la tâche du développeur.
Le support des transactions par Spring de manière déclarative se fait à deux niveaux :
 une définition via des métadonnées en utilisant la configuration ou des annotations. Les métadonnées sont utilisées pour réaliser le tissage des aspects relatifs à la
gestion des transactions (AspectJ).
 l'utilisation de proxys grâce à Spring AOP
 
3.4. La déclaration des transactions dans la configuration du contexte
La déclaration des transactions dans la configuration du contexte se fait dans le fichier XML en utilisant les espaces de nommage tx et aop.
Il faut définir un gestionnaire de transactions (TransactionManager) spécifique au mode de fonctionnement des accès aux données.
Il faut définir un advice lié au gestionnaire de transactions qui va permettre de définir le mode de propagation des transactions dans les méthodes désignées par des motifs.
Il faut enfin définir la configuration des aspects à tisser sur les méthodes qui doivent être transactionnelles. Celles-ci sont définies via des points de coupe grâce à des motifs
auxquels sont associés un advice.

Exemple :

63
Formation  : Développement JEE avec Spring

?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:aop="http://www.springframework.org/schema/aop"
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/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
 
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource" />
</bean>
 
<tx:advice id="serviceTxAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
 
</tx:advice>
 
<tx:advice id="daoTxAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="find*" propagation="REQUIRED" />
<tx:method name="*" propagation="MANDATORY" />
</tx:attributes>
</tx:advice>

64
Formation  : Développement JEE avec Spring

 
<aop:config>
<aop:pointcut id="serviceMethodes" expression="execution(*alti.formation.spring.service.*ServiceImpl.*(..))" />
<aop:advisor advice-ref="serviceTxAdvice" pointcut-ref="serviceMethodes" />
</aop:config>
 
<aop:config>
<aop:pointcut id="daoMethodes"
expression="execution(*alti.formation.spring.dao.*DaoImpl*.*(..))" />
<aop:advisor advice-ref="daoTxAdvice" pointcut-ref="daoMethodes" />
</aop:config>
 
</beans>

Un advice est défini sous le nom txAdvice en lui associant le TransactionManager grâce à l'attribut transaction-manager : les méthodes dont le nom commence par get sont en
lecture seule, les autres méthodes sont en lecture/écriture qui est le mode par défaut.
Le tag <tx:advice/> possède plusieurs attributs :

nom de
Rôle Valeur par défaut
l'attribut

Propagation Préciser le mode de propagation de la transaction REQUIRED

Isolation Préciser le niveau d'isolation DEFAULT

Préciser si la transaction est en lecture seule ou


Transaction read/write
lecture/écriture

par défaut, c'est le timeout du gestionnaire de transactions sous-jacent utilisé, ou aucun si aucun
Timeout Préciser le timeout avant le rollback de la transaction
timeout n'est supporté

Le tag <tx:method/> possède plusieurs attributs :

Nom de l'attribut Rôle Valeur par défaut

Name nom de la ou des méthodes concernées en utilisant un motif dans lequel le caractère * peut être utilisé (exemple : get*) (obligatoire)  

Propagation mode de propagation de la transaction REQUIRED

65
Formation  : Développement JEE avec Spring

Isolation niveau d'isolation de la transaction DEFAULT

Timeout timeout de la transaction en secondes -1

read-only la transaction est en mode lecture seule No

rollback-for la ou les exceptions (séparées par un caractère ";") qui provoquent un rollback de la transaction  

no-rollback-for la ou les exceptions (séparées par un caractère ";") qui ne provoquent pas un rollback de la transaction  

Remarque : par défaut, toutes les exceptions de type RuntimeException provoquent un rollback mais les exceptions de type checked ne provoquent pas de rollback.
Le tag <aop:config> permet la configuration du tissage des aspects relatifs aux transactions en définissant un point de coupe précisé sous la forme d'une expression régulière
d'AspectJ fournie comme valeur de l'attribut expression.
Grace au tissage, l'advice sera exécuté lors de l'invocation de chaque méthode définie par le point de coupe.
Généralement, toutes les méthodes des services doivent être transactionnelles. Pour cela, le point de coupe doit utiliser une expression qui désigne toutes les méthodes et tous

les services.

Exemple :
<aop:config>
<aop:pointcut id="serviceMethodes" expression="execution(*
alti.formation.spring.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethodes"/>
</aop:config>

La gestion des transactions dans les services n'est pas toujours aussi générique et il peut être nécessaire de définir plusieurs pointcuts et advisors pour différentes configurations
transactionnelles.

Exemple :
<?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:aop="http://www.springframework.org/schema/aop"
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

66
Formation  : Développement JEE avec Spring

http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:config>
<aop:pointcut id="defaultServiceOperation"
expression="execution(* alti.formation.spring.*Service.*(..))" />
<aop:pointcut id="noTxServiceOperation"
expression="execution(*alti.formation.spring.*Cache.*(..))" />
 
<aop:advisor pointcut-ref="defaultServiceOperation"
advice-ref="defaultTxAdvice" />
<aop:advisor pointcut-ref="noTxServiceOperation"
advice-ref="noTxAdvice" />
</aop:config>
 
<tx:advice id="defaultTxAdvice">
<tx:attributes>
tx:method name="get*" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>
 
<tx:advice id="noTxAdvice">
<tx:attributes>
<tx:method name="*" propagation="NEVER" />
</tx:attributes>
</tx:advice>
 
<bean id="personneService" class="alti.formation.spring.service.PersonneServiceImpl" />
 
<bean id="personneCache" class="alti.formation.spring.service.cache.PersonneCache" />
 
</beans>

67
Formation  : Développement JEE avec Spring

3.5 Un exemple de déclaration de transactions dans la configuration


Cette section fourni un exemple complet de déclaration d'un service dont les méthodes sont transactionnelles. La configuration des transactions se fait dans la configuration du
contexte de l'application.
Le service est défini par une interface

Exemple :
package alti.formation.spring.service;
 
import java.util.List;
 
import alti.formation.spring.Personne;
 
public interface PersonneService
{
void ajouter(Personne personne);
 
Personne getParId(long id);
 
List<Personne> getTous();
 
void modifier(Personne personne);
}

Le service implémente l'interface.

Exemple :
package alti.formation.spring.service;
 
import java.util.List;
import alti.formation.spring.Personne;
 
public class PersonneServiceImpl implements PersonneService {
@Override
public void ajouter(final Personne personne) {
throw new UnsupportedOperationException();
}
 

68
Formation  : Développement JEE avec Spring

@Override
public Personne getParId(final long id) {
throw new UnsupportedOperationException();
}
 
@Override
public List<Personne> getTous() {
throw new UnsupportedOperationException();
}
 
@Override
public void modifier(final Personne personne) {
throw new UnsupportedOperationException();
}
}

Comme l'implémentation de toutes les méthodes du service lève une exception de type RuntimeException, les transactions provoqueront un rollback.
Les méthodes suffixées par get sont en lecture seule (read-only) alors que les autres méthodes sont utilisées pour des mises à jour (read-write).

Exemple :
<?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:aop="http://www.springframework.org/schema/aop"
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/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

<tx:advice id="txAdvice" transaction-manager="txManager">

69
Formation  : Développement JEE avec Spring

<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:methodname="*" />
</tx:attributes>

</tx:advice>
<aop:config>
<aop:pointcut id="personneServiceOperation"
expression="execution(*
alti.formation.spring.service.PersonneService.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="personneServiceOperation" />
</aop:config>

<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">


<property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver" />
<property name="url" value="jdbc:derby://localhost/MaBaseDeTest" />
<!--  property name="username" value="" / -->
<!--   property name="password" value="" / -->
</bean>

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">


<property name="dataSource" ref="datasource" />
</bean>
<bean id="personneService" class="alti.formation.spring.service.PersonneServiceImpl" />
</beans>

Dans l'exemple ci-dessous, le point de coupe concerne toutes les méthodes de la classe PersonneService en définissant un advisor qui lie le point de coupe et l'advice.
Le PlatformTransactionManager est défini sous la forme d'un bean nommé txManager.
L'utilisation des transactions est alors transparente dans le code appelant.

Exemple :
package alti.formation.spring;

import org.apache.log4j.Logger;
import org.springframework.context.support.ClassPathXmlApplicationContext;

70
Formation  : Développement JEE avec Spring

import alti.formation.spring.Personne;
import alti.formation.spring.PersonneService;
 
public class MonApp
{
private static Logger LOGGER = Logger.getLogger(MonApp.class);
 
public static void main(final String[] args) throws Exception
{
LOGGER.info("Debut de l'application");
 
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] {"appContext.xml" });

PersonneService personneService = (PersonneService) appContext.getBean("personneService");


 
LOGGER.info("Debut invocation du service");
try
{
personneService.ajouter(new Personne());
}
catch (Exception e)
{
LOGGER.error("exception " + e.getClass().getName() + " interceptee");
}
 
LOGGER.info("Fin invocation du service");
LOGGER.info("Fin de l'application");
}
}

L'application de test charge le contexte, lui demande une instance du service et invoque sa méthode ajouter().

Le niveau de traces dans fichier de configuration de Log4J est configuré sur debug pour permettre de voir le détail des actions réalisées par Spring pour gérer les transactions .

Exemple :
<?xml version="1.0" encoding= "UTF-8" ?>

71
Formation  : Développement JEE avec Spring

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">


<log4j:configuration
xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %p [%c] -%m%n"/>
</layout>
</appender>
 
<root>
<priority value="debug"/>
<appender-ref ref="stdout"/>
</root>
</log4j:configuration>

Le classpath de l'application contient les bibliothèques requises :


org.springframework.transaction-3.0.5.RELEASE.jar, org.springframework.aop-3.0.5.RELEASE.jar, org.springframework.asm-3.0.5.RELEASE.jar, org.springframework.aspects-
3.0.5.RELEASE.jar, org.springframework.beans-3.0.5.RELEASE.jar, org.springframework.context-3.0.5.RELEASE.jar, org.springframework.core-3.0.5.RELEASE.jar,
org.springframework.expression-3.0.5.RELEASE.jar, com.springsource.org.apache.commons.logging-1.1.1.jar, com.springsource.org.aopalliance-1.0.0.jar, commons-dbcp-1.4.jar,
com.springsource.org.apache.commons.pool-1.5.3.jar, org.springframework.jdbc-3.0.5.RELEASE.jar, derbyclient.jar, derbynet.jar, org.springframework.instrument-
3.0.5.RELEASE.jar, spring-aspects-3.0.5.RELEASE.jar, log4j-1.2.16.jar
La JVM est lancée avec l'option -javaagent:C:/java/api/aspectjweaver/aspectjweaver-1.6.1.jar pour activer l'agent AspectJ qui va se charger de tisser les aspects au runtime,
notamment ceux concernant les transactions déclarées dans la configuration.
Lors de l'exécution de l'application, l'appel de la méthode du service provoque un rollback puisqu'une exception de type runtime est levée durant ses traitements.

Résultat :
2013-04-28 22:16:07,937  INFO [alti.formation.spring.MonApp] Debut de l'application
...
2013-04-28 22:16:10,000 DEBUG [org.springframework.beans.factory.support.
DefaultListableBeanFactory] Returning cached instance of singleton bean 'personneService'
2013-04-28 22:16:10,000  INFO [alti.formation.spring.MonApp] Debut invocation du service
2013-04-28 22:16:10,031 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Creating new transaction with name

72
Formation  : Développement JEE avec Spring

[alti.formation.service.PersonneServiceImpl.ajouter]:
PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2013-04-28 22:16:11,093 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Acquired Connection [jdbc:derby://localhost:1527/MaBaseDeTest,
UserName=APP, Apache Derby Network Client JDBC Driver] for JDBC transaction
2013-04-28 22:16:11,109 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Switching JDBC Connection [jdbc:derby://localhost:1527/
MaBaseDeTest, UserName=APP, Apache Derby Network Client JDBC Driver] to manual commit
2013-04-28 22:16:11,109 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Initiating transaction rollback
2013-04-28 22:16:11,109 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Rolling back JDBC transaction on Connection [jdbc:derby:
//localhost:1527/MaBaseDeTest, UserName=APP, Apache Derby Network Client JDBC Driver]
2013-04-28 22:16:11,109 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Releasing JDBC Connection [jdbc:derby://localhost:1527/
MaBaseDeTest, UserName=APP, Apache Derby Network Client JDBC Driver] after transaction
2013-04-28 22:16:11,109 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils]
Returning JDBC Connection to DataSource
2013-04-28 22:16:11,109 ERROR [alti.formation.spring.MonApp]
exception java.lang.UnsupportedOperationException interceptee
2013-04-28 22:16:11,109  INFO [alti.formation.spring.MonApp] Fin invocation du service
2013-04-28 22:16:11,109  INFO [alti.formation.spring.MonApp] Fin de l'application

Si la méthode du service ne lève pas d'exception durant son invocation, la transaction est validée par un commit.

Résultat :
2011-04-28 22:18:05,609  INFO
[alti.formation.spring.MonApp] Debut de l'application
...
2011-04-28 22:18:07,625  INFO
[alti.formation.spring.MonApp] Debut invocation du service
2011-04-28 22:18:07,671 DEBUG
[org.springframework.jdbc.datasource.DataSourceTransactionManager] Creating new
transaction with name [alti.formation.spring.service.PersonneServiceImpl.ajouter]:
PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2011-04-28 22:18:08,703 DEBUG
[org.springframework.jdbc.datasource.DataSourceTransactionManager] Acquired

73
Formation  : Développement JEE avec Spring

Connection [jdbc:derby://localhost:1527/MaBaseDeTest, UserName=APP, Apache


Derby Network Client JDBC Driver] for JDBC transaction
2011-04-28 22:18:08,734 DEBUG
[org.springframework.jdbc.datasource.DataSourceTransactionManager] Switching
JDBC Connection [jdbc:derby://localhost:1527/MaBaseDeTest, UserName=APP, Apache
Derby Network Client JDBC Driver] to manual commit
2011-04-28 22:18:08,734 DEBUG
[org.springframework.jdbc.datasource.DataSourceTransactionManager] Initiating
transaction commit
2011-04-28 22:18:08,734 DEBUG
[org.springframework.jdbc.datasource.DataSourceTransactionManager] Committing
JDBC transaction on Connection [jdbc:derby://localhost:1527/MaBaseDeTest,
UserName=APP, Apache Derby Network Client JDBC Driver]
2011-04-28 22:18:08,734 DEBUG
[org.springframework.jdbc.datasource.DataSourceTransactionManager] Releasing
JDBC Connection [jdbc:derby://localhost:1527/MaBaseDeTest, UserName=APP, Apache
Derby Network Client JDBC Driver] after transaction
2011-04-28 22:18:08,734 DEBUG
[org.springframework.jdbc.datasource.DataSourceUtils] Returning JDBC Connection
to DataSource
2011-04-28 22:18:08,734  INFO
[com.jmdoudoux.test.spring.MonApp] Fin invocation du service
2011-04-28 22:18:08,734  INFO
[com.jmdoudoux.test.spring.MonApp] Fin de l'application

3.6 La déclaration des transactions avec des annotations


L'annotation @Transactional peut être utilisée pour indiquer au conteneur qu'elles sont les méthodes qui doivent s'exécuter dans un contexte transactionnel.
Si la déclaration des transactions se fait avec des annotations, il est tout même nécessaire de déclarer le gestionnaire de transactions dans la configuration du contexte de Spring.
Pour permettre une utilisation de l'annotation @Transactional, il faut utiliser le tag <annotation-driven> de l'espace de nommage tx pour préciser à Spring que les annotations
sont utilisées pour la définition des transactions.
Son attribut transaction-manager permet de préciser l'identifiant du bean qui encapsule le gestionnaire de transactions (TransactionManager) utilisé pour gérer les transactions :
son utilisation n'est obligatoire que si l'id du gestionnaire de transactions est différent de "transactionManager".

Exemple :
74
Formation  : Développement JEE avec Spring

<beans>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="datasource" ref="dataSource"
</bean>
 
<tx:annotation-driven transaction-manager="txManager"/>
 
<!-- ... -->
</beans>

La définition des transactions avec une annotation est plus simple à mettre en oeuvre, car il suffit d'annoter chaque méthode ou classe concernée avec @Transactional au lieu de
la définir par des expressions régulières dans le fichier de configuration.
L'annotation org.springframework.transaction.annotation.Transactionnal s'utilise sur une classe ou une méthode. Sur une classe, elle s'applique automatiquement sur toutes les
méthodes publiques de la classe.
L'annotation @Transactional possède plusieurs attributs :
 propagation : précise le mode de propagation de la transaction grâce à une énumération de type Propagation. La valeur par défaut est Propagation.REQUIRED
 readonly : booléen qui précise de façon informative au système de gestion des transactions sous-jacent si la transaction est en lecture seule (true) ou si elle effectue des
mises à jour (false)
 isolation : précise le niveau d'isolation de la transaction grâce à une énumération de type Isolation. La valeur par défaut est Isolation.DEFAULT
 timeout : entier qui précise le timeout de la transaction

Exemple :
package alti.formation.spring.service;
 
@Service("personneService")
@Transactional
public class PersonneServiceImpl implements PersonneService {
//...
 
@Transactional(readOnly=true)
public List<Personne> findAll() throws ServiceException {
//...
}
75
Formation  : Développement JEE avec Spring

 
//...
}

Il est fortement recommandé d'utiliser l'annotation @Transactional sur des classes et non sur des interfaces.
L'avantage de mettre en oeuvre les transactions par AOP est qu'il n'est pas nécessaire d'utiliser une API de Spring dans le code pour mettre en oeuvre les transactions. La mise en
oeuvre reste aussi la même quelque soit l'implémentation du gestionnaire de transactions utilisées : la seule chose qui change c'est la configuration du transaction manager
utilisé.

3.7 L'utilisation de l'annotation @Transactional


L'annotation @Transactional permet de délimiter une transaction (entre le début et la fin de la méthode) et de définir le comportement transactionnel d'une méthode.
L'annotation @Transactional possède plusieurs attributs :

Nom de l'attribut Rôle Valeur par défaut

propagation mode de propagation de la transaction PROPAGATION_REQUIRED

isolation niveau d'isolation de la transaction ISOLATIONDEFAULT

read-write indique si la transaction est en lecture seule (false) ou  

lecture/écriture(true) true  

valeur par défaut de l'implémentation du système de


timeout  
gestion des transactions utilisé

ensemble d'exceptions héritant de Throwable qui provoquent un rollback de la


rollbackFor  
transaction si elles sont levées durant les traitements

ensemble de noms de classes héritant de Throwable qui provoquent un rollback de la


rollbackForClassname  
transaction s'ils sont levés durant les traitements

ensemble d'exceptions héritant de Throwable qui ne provoquent pas un rollback de la


noRollbackFor  
transaction si elles sont levées durant les traitements
76
Formation  : Développement JEE avec Spring

ensemble de noms de classes héritant de Throwable qui ne provoquent pas un rollback


noRollbackForClassname  
de la transaction si ils sont levés durant les traitements

La simple utilisation de l'annotation @Transactional ne suffit pas car c'est simplement des métadonnées : il faut obligatoirement utiliser le tag <tx:annotation-driven> dans la
configuration pour permettre à Spring d'ajouter les traitements relatifs aux aspects transactionaux sur les méthodes annotées.
Le tag <tx:annotation-driven> possède plusieurs attributs :

Nom de l'attribut Rôle Valeur par défaut

transaction- nom du bean qui encapsule le gestionnaire de transaction (obligatoire uniquement si le nom ne correspond à la valeur par
transaction-manager
manager défaut)

mode les valeurs possibles sont proxy (utilisation de proxys) et aspectj (tissage des aspects avec AspectJ) proxy

Permet de préciser le type de proxy utilisé (true : proxy reposant sur les interfaces, false : proxy reposant sur les classes). Ne
proxy-target-class False
doit être utilisé que si le mode est proxy

Ordered.LOWEST
order Permet de définir l'ordre des traitements exécutés sur les beans annotés avec @Transactional
PRECEDENCE

Attention : le tag <tx:annotation-driven> ne recherche les beans annotés avec @Transactional que dans le contexte dans lequel ils sont définis.
L'annotation @Transactional peut être utilisée sur une classe ou sur une méthode. Utilisée sur une classe, elle s'applique par défaut sur toutes les méthodes public de la classe
sauf si la méthode est elle même annotée avec @Transactional. Dans ce cas, c'est l'annotation sur la méthode qui est utilisée.

Exemple :
@Transactional(readOnly = true)
public class PersonneServicelmpl implements PersonneService {
public Personne getParld(long id) {
// traitements de la methode
}
 
@Transactional(readOnly = false, propagation = Propagation.REQUIRESNEW)
public void modifier(Personne personne) {
// traitements de la methode
}
}

77
Formation  : Développement JEE avec Spring

Seules les méthodes public doivent être annotées avec @Transactional lors de l'utilisation de proxys. Si des méthodes package-friendly, protected ou private sont annotées avec
@Transactional, aucune erreur n'est produite à la compilation mais ces méthodes seront ignorées lors de l'utilisation des proxys.
Il est fortement recommandé de n'utiliser l'annotation @Transactional que dans des classes concrètes surtout dans le mode par défaut, le mode proxy.
Attention : dans le mode proxy, seules les invocations de méthodes depuis d'autres classes seront transactionnelles. Les invocations d'une méthode de la classe par une autre
méthode de la classe ne sont pas transactionnelles même si la méthode invoquée est annotée avec @Transactional car ces invocations ne sont pas interceptées par le proxy.
Dans ce cas, il faut utiliser le mode AspectJ pour permettre un tissage des classes avec les aspects relatifs à la gestion des transactions pour les méthodes annotées. L'utilisation
de ce mode requiert que la bibliothèque spring-aspects.jar soit ajoutée au classpath et le tissage (load-time weaving ou compile-time weaving) soit activé.

3.8 Le support de @Transactional par AspectJ


Il est possible d'utiliser le tissage d'aspects d'AspectJ pour intégrer le bytecode requis par le traitement des annotations @Transactional à la place d'utiliser des proxys gérés par le
conteneur.
L'aspect à tisser est org.springframework.transaction.aspectj.AnnotationTransactionAspect contenu dans la bibliothèque spring-aspects.jar.
Il faut utiliser le tag <tx.annotation-driven> dans la configuration du contexte avec l'attribut mode="aspectj"
Le tissage peut se faire à la compilation ou au runtime.
L'annotation @Transactional peut alors être utilisée sur n'importe quelle méthode quelque soit sa visibilité.

 3.9 Un exemple de déclaration des transactions avec des annotations

L'exemple de cette section va utiliser Spring 3, AspectJ (en mode Load Time Weaving), JavaDB (en mode client/serveur), log4J.
La déclaration des transactions en utilisant les annotations est plus simple à mettre en oeuvre que la déclaration dans la configuration.

Il suffit d'utiliser l'annotation @Transactional sur les méthodes ou sur les classes concernées .

Exemple :
package alti.formation.spring.service;
 
import java.util.List;
 
import alti.formation.spring.Personne;

78
Formation  : Développement JEE avec Spring

 
public interface PersonneService {
void ajouter(Personne personne);
Personne getParId(long id);
List<Personne> getTous();
void modifier(Personne personne);
}

Le service implémente l'interface ci-dessus.

Exemple :
package alti.formation.spring.service;
 
import java.util.List;
 
import org.springframework.transaction.annotation.Transactional;
 
import alti.formation.spring.Personne;
 
public class PersonneServiceImpl implements PersonneService {
 
@Override
@Transactional
public void ajouter(final Personne personne) {
throw new UnsupportedOperationException();
}
 
@Override
@Transactional(readOnly = true)
public Personne getParId(final long id) {
throw new UnsupportedOperationException();
}
 
@Override
@Transactional(readOnly = true)
public List<Personne> getTous() {
79
Formation  : Développement JEE avec Spring

throw new UnsupportedOperationException();


}
 
@Override
@Transactional
public void modifier(final Personne personne)
{ throw new UnsupportedOperationException();
}
}

Dans cette implémentation, toutes les méthodes transactionnelles lève une exception, ce qui permet de tester le rollback de la transaction.
La configuration du contexte est simplifiée car il suffit de déclarer le gestionnaire de transactions à utiliser et d'utiliser le tag <tx:annotation-driven>.

Exemple :
<?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:aop="http:/www.springframework.org/schema/aop"
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/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 
<tx:annotation-driven mode="aspectj" transaction-manager="txManager" />
 
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver" />
<property name="url" value="jdbc:derby://localhost/MaBaseDeTest" />
</bean>
 
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource" />

80
Formation  : Développement JEE avec Spring

/bean>
 
<bean id="personneService" class="alti.formation.spring.service.PersonneServiceImpl" />
</beans>

L'attribut transaction-manager du tag <tx:annotation-driven> permet de préciser l'instance du gestionnaire de transactions à utiliser. Cet attribut peut être facultatif si le nom du
bean du gestionnaire de transaction est "transactionManager".

Exemple :
package alti.formation.spring;
 
import org.apache.log4j.Logger;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import alti.formation.spring.entite.Personne;
import alti.formation.spring.service.PersonneService;
 
public class MonApp {
private static Logger LOGGER = Logger.getLogger(MonApp.class);
 
public static void main(final String[] args) throws Exception {
LOGGER.info("Debut de l'application");
 
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] { "appContext.xml" });
PersonneService personneService = (PersonneService) appContext.getBean("personneService");
LOGGER.info("Debutinvocation du service");
try {
personneService.ajouter(newPersonne());
} catch (Exception e) {
LOGGER.error("exception" + e.getClass().getName() + " interceptee");
}

LOGGER.info("Fin invocation du service");


LOGGER.info("Fin de l'application");
}
}

81
Formation  : Développement JEE avec Spring

L'application de test charge le contexte, lui demande un instance du service et invoque sa méthode ajouter().
Le niveau de traces dans fichier de configuration de Log4J est configuré sur debug pour permettre de voir le détail des actions réalisées par Spring pour gérer les transactions.

Exemple :
<?xml version="1.0" encoding= "UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration
xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %p [%c] - %m%n"/>
</layout>
</appender>
 
<root>
<priority value="debug"/>
<appender-ref ref="stdout"/>
</root>
</log4j:configuration>

Le classpath de l'application contient les bibliothèques requises :


org.springframework.transaction-3.0.5.RELEASE.jar, org.springframework.aop-3.0.5.RELEASE.jar, org.springframework.asm-3.0.5.RELEASE.jar, org.springframework.aspects-
3.0.5.RELEASE.jar, org.springframework.beans-3.0.5.RELEASE.jar, org.springframework.context-3.0.5.RELEASE.jar, org.springframework.core-3.0.5.RELEASE.jar,
org.springframework.expression-3.0.5.RELEASE.jar, com.springsource.org.apache.commons.logging-1.1.1.jar, com.springsource.org.aopalliance-1.0.0.jar, commons-dbcp-1.4.jar,
com.springsource.org.apache.commons.pool-1.5.3.jar, org.springframework.jdbc-3.0.5.RELEASE.jar, derbyclient.jar, derbynet.jar, org.springframework.instrument-
3.0.5.RELEASE.jar, spring-aspects-3.0.5.RELEASE.jar, log4j-1.2.16.jar
La JVM est lancée avec l'option -javaagent:C:/java/api/aspectjweaver/aspectjweaver-1.6.1.jar pour activer l'agent AspectJ qui va se charger de tisser les aspects, notamment
ceux concernant l'annotation @Transactional, au runtime.
Lors de l'exécution de l'application, l'appel de la méthode du service provoque un rollback puisqu'une exception de type runtime est levée durant ses traitements.

Résultat :
2011-04-26 22:17:48,453  INFO [alti.formation.spring.MonApp] Debut de l'application
2011-04-26 22:17:50,187  INFO [alti.formation.spring.MonApp] Debut invocation du service
...

82
Formation  : Développement JEE avec Spring

2011-04-26 22:17:50,218 DEBUG [org.springframework.transaction.annotation


.AnnotationTransactionAttributeSource] Adding transactional method 'ajouter' with attribute:
PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2011-04-26 22:17:50,218 DEBUG [org.springframework.beans.factory.support.
DefaultListableBeanFactory] Returning cached instance of singleton bean 'txManager'
2011-04-26 22:17:50,250 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Creating new transaction with name [com.jmdoudoux.test.spring.
service.PersonneServiceImpl.ajouter]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2011-04-26 22:17:51,296 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Acquired Connection [jdbc:derby://localhost:1527/MaBaseDeTest,
UserName=APP, Apache Derby Network Client JDBC Driver] for JDBC transaction
2011-04-26 22:17:51,328 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Switching JDBC Connection [jdbc:derby://localhost:1527/
MaBaseDeTest, UserName=APP, Apache Derby Network Client JDBC Driver] to manual commit
2011-04-26 22:17:51,328 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Initiating transaction rollback
2011-04-26 22:17:51,328 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Rolling back JDBC transaction on Connection [jdbc:derby:
//localhost:1527/MaBaseDeTest, UserName=APP, Apache Derby Network Client JDBC Driver]
2011-04-26 22:17:51,328 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Releasing JDBC Connection [jdbc:derby://localhost:1527/
MaBaseDeTest, UserName=APP, Apache Derby Network Client JDBC Driver] after transaction
2011-04-26 22:17:51,328 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils]
Returning JDBC Connection to DataSource
2011-04-26 22:17:51,328 ERROR [alti.formation.spring.MonApp]
exception java.lang.UnsupportedOperationException interceptee
2011-04-26 22:17:51,328  INFO [alti.formation.spring.MonApp] Fin invocation du service
2011-04-26 22:17:51,328  INFO [alti.formation.spring.MonApp] Fin de l'application

Si la méthode du service ne lève pas d'exception durant son invocation, la transaction est validée par un commit.

Résultat :
2011-04-26 22:25:17,484  INFO
[alti.formation.spring.MonApp] Debut de l'application
...
2011-04-26 22:25:19,250  INFO
[alti.formation.spring.MonApp] Debut invocation du service

83
Formation  : Développement JEE avec Spring

2011-04-26 22:25:19,296 DEBUG


[org.springframework.transaction.annotation.AnnotationTransactionAttributeSource]
Adding transactional method 'ajouter' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT;''
2011-04-26 22:25:19,296 DEBUG
[org.springframework.beans.factory.support.DefaultListableBeanFactory]
Returning cached instance of singleton bean 'txManager'
2011-04-26 22:25:19,312 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Creating new transaction with name
[alti.formation.spring.service.PersonneServiceImpl.ajouter]:
PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2011-04-26 22:25:20,390 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Acquired Connection [jdbc:derby://localhost:1527/
MaBaseDeTest, UserName=APP, Apache Derby Network Client JDBC Driver] for JDBC transaction
2011-04-26 22:25:20,421 DEBUG
[org.springframework.jdbc.datasource.DataSourceTransactionManager] Switching
JDBC Connection [jdbc:derby://localhost:1527/MaBaseDeTest, UserName=APP, Apache
Derby Network Client JDBC Driver] to manual commit
2011-04-26 22:25:20,421 DEBUG
[org.springframework.jdbc.datasource.DataSourceTransactionManager] Initiating
transaction commit
2011-04-26 22:25:20,421 DEBUG
[org.springframework.jdbc.datasource.DataSourceTransactionManager] Committing
JDBC transaction on Connection [jdbc:derby://localhost:1527/MaBaseDeTest,
UserName=APP, Apache Derby Network Client JDBC Driver]
2011-04-26 22:25:20,421 DEBUG
[org.springframework.jdbc.datasource.DataSourceTransactionManager] Releasing
JDBC Connection [jdbc:derby://localhost:1527/MaBaseDeTest, UserName=APP, Apache
Derby Network Client JDBC Driver] after transaction
2011-04-26 22:25:20,421 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils]
Returning JDBC Connection to DataSource
2011-04-26 22:25:20,421  INFO
[alti.formation.spring.MonApp] Fin invocation du service
2011-04-26 22:25:20,421  INFO
[alti.formation.spring.MonApp] Fin de l'application

84
Formation  : Développement JEE avec Spring

3.10. La gestion du rollback des transactions


Spring utilise des règles particulières reposant sur les exceptions pour effectuer un rollback au besoin de la transaction. Par défaut, un rollback est effectué si une exception de
type unchecked est levée dans les traitements de la transaction.
Ainsi par défaut, une transaction est annulée (rollback) si une exception de type RuntimeException ou Error est levée durant les traitements exécutés dans le contexte de la
transaction. Donc par défaut, une transaction n'est pas annulée si une exception de type checked est levée dans les traitements.
Spring permet cependant une configuration fine des types d'exceptions qui vont provoquer un rollback de la transaction  : ces règles peuvent être adaptées dans la déclaration de
la transaction en précisant quelles exceptions provoquent un rollback ou non.
Il est aussi possible de forcer un rollback de la transaction par programmation en invoquant la méthode setRollback0nly() sur l'objet de type TransactionStatus.

 3.11 La gestion du rollback dans la configuration

Si les transactions sont définies dans la configuration du contexte, les attributs rollback-for et no-rollback-for du tag <tx:method> permettent respectivement de préciser la ou les
types d'exceptions qui vont provoquer un rollback ou non.

Exemple :
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" rollback-for="MonException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

Dans cet exemple, un rollback de la transaction sera exécuté par Spring si une exception de type MonException est levée durant les traitements du contexte transactionnel.

Exemple :
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" no-rollback-for="MonAutreException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>

85
Formation  : Développement JEE avec Spring

Dans cet exemple, un commit de la transaction sera exécuté par Spring si une exception de type MonAutreException est levée durant les traitements du contexte transactionnel
sans autre exception.

Exemple :
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*" rollback-for="Throwable" no-rollback-for="MonException"/>
</tx:attributes>
</tx:advice>

Dans l'exemple ci-dessus, seule l'exception MonException ne va pas provoquer un rollback de la transaction.

3.12. La gestion du rollback via l'API

Il est aussi possible de forcer le rollback de la transaction par programmation en utilisant l'API.

Exemple :
public void maMethode() {
try {
// traitements
} catch (MonException ex) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}

Cette solution impose d'utiliser l'API de Spring ce qui n'est pas la meilleure solution : il est préférable dans la mesure du possible d'utiliser l'approche déclarative.

3.13 La gestion du rollback avec les annotations


L'annotation @Transactional possède plusieurs attributs permettant de gérer finement un éventuel rollback de la transaction.
L'attribut rollbackFor permet de préciser un tableau d'exceptions héritant de Throwable qui provoquent un rollback de la transaction si elles sont levées durant les traitements.
L'attribut rollbackForClassname permet de préciser un tableau de noms de classes héritant de Throwable qui provoquent un rollback de la transaction s'ils sont levés durant les
traitements.
86
Formation  : Développement JEE avec Spring

L'attribut noRollbackFor permet de préciser un tableau d'exceptions héritant de Throwable qui ne provoquent pas un rollback de la transaction si elles sont levées durant les
traitements.
L'attribut noRollbackForClassname permet de préciser un tableau de noms de classes héritant de Throwable qui ne provoquent pas un rollback de la transaction s'ils sont levés
durant les traitements.
Ces quatre attributs permettent de configurer de façon précise les conditions selon lesquelles un rollback de la transaction sera fait par les traitements de l'annotation
@Transactional.

 3.15. La mise en oeuvre d'aspects sur une méthode transactionnelle

Les transactions sont mises en oeuvre grâce à l'AOP mais il est aussi possible d'utiliser l'AOP pour ses propres besoins sur des méthodes transactionnelles.
Spring offre un moyen de configurer l'ordre d'exécution de ces aspects en implémentant l'interface Ordered.

Exemple :
package alti.formation.spring;
 
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
import org.springframework.core.Ordered;
 
public class MonitoringPerf implements Ordered {
private int order;
 
public int getOrder() {
return this.order;
}
 
public void setOrder(int order) {
this.order = order;
}
 
public Object executer(ProceedingJoinPoint call) throws Throwable {
Object returnValue;
StopWatch clock = new StopWatch(getClass().getName());
try {

87
Formation  : Développement JEE avec Spring

clock.start(call.toShortString());
returnValue = call.proceed();
}
finally {
clock.stop();
System.out.println(clock.prettyPrint());
}
return returnValue;
}
}

Il faut définir l'aspect dans le fichier de configuration du contexte et préciser l'ordre d'invocation des aspects.
Le fichier de configuration en déclarant les transactions par annotations

Exemple :
<?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:aop="http://www.springframework.org/schema/aop"
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/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 
<tx:annotation-driven mode="aspectj"
transaction-manager="txManager" order="99" />
 
<aop:config>
<aop:aspect id="monitorerPerfAspect" ref="monitorerPerf">
<aop:pointcut id="methodeService"
expression="execution(* alti.formation.spring.service.*ServiceImpl.*(..))" />
<aop:around method="executer" pointcut-ref="methodeService" />
</aop:aspect>
88
Formation  : Développement JEE avec Spring

</aop:config>
 
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver" />
<property name="url" value="jdbc:derby://localhost/MaBaseDeTest" />
</bean>
 
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource" />
</bean>
 
<bean id="monitorerPerf" class="alti.formation.spring.MonitorerPerf">
<property name="order" value="1" />
</bean>
 
<bean id="personneService" class="alti.formation.spring.service.PersonneServiceImpl" />
 
</beans>

L'ordre d'invocation des aspects est défini grâce à la valeur fournie aux attributs order du bean qui encapsule l'aspect et de l'attribut order du tag <annotation-driven>.
Le fichier de configuration en déclarant les transactions dans le fichier de configuration

Exemple :
<?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:aop="http://www.springframework.org/schema/aop"
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/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd

89
Formation  : Développement JEE avec Spring

http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>
 
<aop:config>
<aop:pointcut id="personneServiceOperation" expression="execution(* alti.formation.spring.PersonneService.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="personneServiceOperation"
order="99" />
 
<aop:aspect id="monitorerPerfAspect" ref="monitorerPerf">
<aop:around method="executer" pointcut-ref="personneServiceOperation" />
</aop:aspect>
 
</aop:config>
 
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver" />
<property name="url" value="jdbc:derby://localhost/MaBaseDeTest" />
</bean>
 
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource" />
</bean>
 
<bean id="monitorerPerf" class="alti.formation.MonitorerPerf">
<property name="order" value="1" />
</bean>
 
<bean id="personneService" class="alti.formation.PersonneServiceImpl" />
 
</beans>
90
Formation  : Développement JEE avec Spring

L'ordre d'invocation des aspects est défini grâce à la valeur fournie aux attributs order du bean qui encapsule l'aspect et de l'advisor qui concerne la gestion des transactions.
L'exécution de l'application affiche le temps d'exécution suite à l'invocation de la méthode

Résultat :
2011-04-28 22:27:47,375  INFO [alti.formation.spring.MonApp] Debut de l'application
...
2011-04-28 22:27:49,578  INFO [alti.formation.spring.MonApp] Debut invocation du service
2011-04-28 22:27:49,593 DEBUG [org.springframework.beans.factory.support.
DefaultListableBeanFactory] Returning cached instance of singleton bean 'monitorerPerf'
2011-04-28 22:27:49,640 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Creating new transaction with name
[ alti.formation.spring.PersonneServiceImpl.ajouter]:
PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2011-04-28 22:27:50,687 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Acquired Connection
[jdbc:derby://localhost:1527/MaBaseDeTest, UserName=APP, Apache Derby Network Client
JDBC Driver] for JDBC transaction
2011-04-28 22:27:50,703 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Switching JDBC Connection
[jdbc:derby://localhost:1527/MaBaseDeTest, UserName=APP, Apache Derby Network Client
JDBC Driver] to manual commit
2011-04-28 22:27:50,703 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Initiating transaction commit
2011-04-28 22:27:50,703 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Committing JDBC transaction on Connection [jdbc:derby:
//localhost:1527/MaBaseDeTest, UserName=APP, Apache Derby Network Client JDBC Driver]
2011-04-28 22:27:50,703 DEBUG [org.springframework.jdbc.datasource.
DataSourceTransactionManager] Releasing JDBC Connection
[jdbc:derby://localhost:1527/MaBaseDeTest, UserName=APP, Apache Derby Network Client
JDBC Driver] after transaction
2011-04-28 22:27:50,703 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils]
Returning JDBC Connection to DataSource
2011-04-28 22:27:50,703 DEBUG [alti.formation.spring.MonitorerPerf]
temps d'execution : StopWatch
'com.jmdoudoux.test.spring.aspect.MonitorerPerf': running time (millis) = 1094
-----------------------------------------
ms     %     Task name

91
Formation  : Développement JEE avec Spring

-----------------------------------------
01094  100 %  execution(PersonneService.ajouter(..))
 
2011-04-28 18:27:50,703  INFO [alti.formation.spring.MonApp] Fin invocation du service
2011-04-28 18:27:50,703  INFO [alti.formation.spring.MonApp] Fin de l'application

3.16 L'utilisation des transactions via l'API


Pour la mise en oeuvre des transactions par programmation, Spring propose deux solutions :
 utiliser la classe TransactionTemplate
 utiliser directement une implémentation de l'interface PlatformTransactionManager
L'utilisation de ces deux solutions lie fortement le code de l'application avec Spring puisqu'elles utilisent des API dédiées. Elles ne sont donc à utiliser que pour des besoins très
spécifiques et il est préférable d'utilisable une solution déclarative.

 3.17 L'utilisation de la classe TransactionTemplate

Le principe de la classe TransactionTemplate repose sur l'utilisation de callbacks comme pour les autres templates Spring.
Il faut écrire une implémentation de TransactionCallback, généralement sous la forme d'une classe anonyme interne, qui va contenir les traitements à exécuter dans le contexte
transactionnel.
Il suffit alors de passer une instance de cette implémentation en paramètre de la méthode execute() de la classe TransactionTemplate.

Exemple :
package alti.formation.spring;
 
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
 
import alti.formation.spring.Personne;
 

92
Formation  : Développement JEE avec Spring

public class MonServiceImpl implements MonService {


 
private final TransactionTemplate transactionTemplate;
 
public MonServiceImpl(final PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
 
protected boolean maMethode(final Personne personne) {
// traitement de la methode
return true;
}
 
public Object maMethodeTransactionelle(final Personne personne) {
return transactionTemplate.execute(new TransactionCallback() {
 
public Object doInTransaction(final TransactionStatus status) {
return maMethode(personne);
}
});
}
}

L'instance de TransactionTemplate est utilisée par toutes les méthodes d'instances.


L'injection de l'instance du gestionnaire de transactions ce fait via le constructeur.
Si la méthode transactionnelle ne renvoie aucun résultat, il faut utiliser la classe TransactionCallbackWithoutResult.

Exemple :
package alti.formation.spring;
 
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
 

93
Formation  : Développement JEE avec Spring

import alti.formation.spring.Personne;
 
public class MonServiceImpl implements MonService {
 
private final TransactionTemplate transactionTemplate;
 
public MonServiceImpl(final PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
 
protected void maMethode(final Personne personne) {
// traitement de la methode
}
 
public Object maMethodeTransactionelle(final Personne personne) {
return transactionTemplate.execute(new TransactionCallbackWithoutResult() {
 
public void doInTransactionWithoutResult(final TransactionStatus status) {
maMethode(personne);
}
});
}
}

Il est possible de demander explicitement l'annulation de la transaction dans le code du callback en invoquant la méthode setRollbackOnly() de l'instance de TransactionStatus
fournie en paramètre.

Exemple :
package alti.formation.spring;
 
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
 

94
Formation  : Développement JEE avec Spring

import alti.formation.spring.Personne;
 
public class MonServiceImpl implements MonService {
 
private final TransactionTemplate transactionTemplate;
 
public MonServiceImpl(final PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
 
protected boolean maMethode(final Personne personne) {
// traitement de la methode
return true;
}
 
public Object maMethodeTransactionelle(final Personne personne) {
return transactionTemplate.execute(new TransactionCallback() {
 
@Override
public Object doInTransaction(final TransactionStatus status) {
boolean resultat = false;
try {
resultat = maMethode(personne);
} catch (MonException ex) {
status.setRollbackOnly();
}
return resultat;
}
});
}
}

La classe TransactionTemplate possède plusieurs méthodes pour permettre de configurer le contexte transactionnel.

Exemple :
01.package com.jmdoudoux.test.spring.service;

95
Formation  : Développement JEE avec Spring

02. 
03.import org.springframework.transaction.PlatformTransactionManager;
04.import org.springframework.transaction.TransactionDefinition;
05.import org.springframework.transaction.TransactionStatus;
06.import org.springframework.transaction.support.TransactionCallback;
07.import org.springframework.transaction.support.TransactionTemplate;
08. 
09.import com.jmdoudoux.test.spring.entite.Personne;
10. 
11.public class MonServiceImpl implements MonService {
12. 
13.private final TransactionTemplate transactionTemplate;
14. 
15.public MonServiceImpl(final PlatformTransactionManager transactionManager) {
16.this.transactionTemplate = new TransactionTemplate(transactionManager);
17.this.transactionTemplate
18..setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
19.this.transactionTemplate.setTimeout(60);
20. 
21.}
22. 
23.// ...
24.}

Les instances de TransactionTemplate sont threadsafe mais elles contiennent la configuration. Il est donc possible de partager une instance de TransactionTemplate mais il est
nécessaire d'avoir autant d'instance que de configuration différente.

Il est donc possible de déclarer un bean de type TransactionTemplate et de le paramétrer dans la configuration puis de l'injecter dans les services qui en ont besoin .

Exemple :
<bean id="monTransactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
 
<property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED" /> 
<property name="timeout" value="30" />
 
</bean>
96
Formation  : Développement JEE avec Spring

3.18 L'utilisation directe d'un PlatformTransactionManager


Par programmation, il est possible d'utiliser directement une instance de type PlatformTransactionManager pour gérer les transactions.
Dans le bean, il faut permettre une injection de l'instance de PlatformTransactionManager par Spring.
L'interface TransactionDefinition définit la configuration d'une transaction.
Le plus simple est de créer une instance de la classe DefaultTransactionDefinition puis d'invoquer sa méthode setName() pour lui attribuer un nom et invoquer toutes les
méthodes utiles pour configurer la transaction.
La méthode getTransaction() qui attend en paramètre une instance de TransactionDefinition renvoie une instance de l'interface TransactionStatus.
L'interface TransactionStatus définit le statut d'une transaction. Elle propose plusieurs méthodes :

Méthode Rôle

boolean hasSavepoint() Renvoie un booléen qui précise si la transaction a été créée comme englobée dans une transaction possédant un savepoint

boolean isCompleted() Renvoie un booléen qui précise si la transaction est terminée (par un rollback ou un commit)

boolean isNewTransaction() Renvoie un booléen qui précise si la transaction est nouvelle

boolean isRollbackOnly() Renvoie un booléen qui précise si la transaction est marquée comme devant être annulée
void setRollbackOnly() Demande l'annulation de la transaction

Exemple :
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("MaTransaction");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
// les traitements
} catch (MonException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);

97
Formation  : Développement JEE avec Spring

98
Formation  : Développement JEE avec Spring

4 Scheduler
Le framework Spring permet de créer des traitements de types taches ordonnancées (scheduled tasks).

4.1 Définition d’une tache programmée (Scheduler Task)


La définition d’une tache programmée requiert que l’on nécessite que l’on crée une classe, puis que l’on déclare un bean, de la manière suivante :
package alti.formation.spring;
 
public class RunMeTask
{
public void printMe() {
System.out.println("Execution");
}
}

Dans les étapes suivantes :


- On déclare le bean correspondant à la classe du traitement programmée
<bean id="runMeTask" class="alti.formation.spring.RunMeTask" />

- On reference le bean et la méthode qui seront executées comme une tache ordonnancée (plannifiée):
<bean id="schedulerTask" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
<property name="targetObject" ref="runMeTask" />
<property name="targetMethod" value="printMe" />
</bean>

- On définit ensuite la périodicité et le temps de latence du la tache programmée :


<bean id="timerTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask" ref="schedulerTask" />
<property name="delay" value="1000" />
<property name="period" value="60000" />
</bean>

Remarques : 
a)
- Enfin, on déclare dans le bean Spring qui correspond à la fabrique de de Timer la tache programmée :

99
Formation  : Développement JEE avec Spring

<bean class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref local="timerTask" />
</list>
</property>
</bean>
 

Le cntenu global du fichier de définition du contexte d’application Spring (applicationContext.xml) est le suivant :
<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">

<bean id="runMeTask" class="alti.formation.spring.RunMeTask" />


 
 
 
<bean id="timerTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask" ref="schedulerTask" />
<property name="delay" value="1000" />
<property name="period" value="60000" />
</bean>
 
<bean class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref local="timerTask" />
</list>
</property>
</bean>
 
</beans>

100
Formation  : Développement JEE avec Spring

Le code source permettant de tester l’exécution du schéduler :


package alti.formation.spring;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class App
{
public static void main( String[] args )
{
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}

No code need to call the scheduler task, the TimerFactoryBean will run your schedule task during start up. As result, Spring scheduler will run the
printMe() method every 60 seconds, with a 1 second delay for the first time of execution.

Conclusion

Most of the Spring developers are just implements the ‘Around advice ‘, since it can apply all the advice type, but a better practice should choose the
most suitable advice type to satisfy the requirements.

101
Formation  : Développement JEE avec Spring

Configuration des clients

La configuration Hessian standard est la suivante

<!– Hessian client –>


<bean id="HessianCustomerServiceProxy" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl" value="${url}"/>
<property name="serviceInterface"
value="com.onx.spring.remoting.services.CustomerService"/>
</bean>

La valeur de l’url est : http://localhost:8080/services/HessianCustomerService

Le nom de la servlet et le nom du service sont référencés.

 
Il est possible d’activer le protocole Hessian 2 (recommandé) qui est plus performant en changeant la propriété proxyFactory du bean déclaré

<!– Enable Hessian 2 protocol –>

102
Formation  : Développement JEE avec Spring

<property name="proxyFactory">
<bean class="com.caucho.hessian.client.HessianProxyFactory">
<property name="hessian2Request" value="true" />
<property name="hessian2Reply" value="true" />
</bean>
</property>

Pour Burlap et http invoker les Proxy à utiliser sont les suivants :

<!– Burlap client –>


<bean id="BurlapCustomerServiceProxy" class="org.springframework.remoting.caucho.BurlapProxyFactoryBean">
<property name="serviceUrl" value="${url}"/>
<property name="serviceInterface"
value="com.onx.spring.remoting.services.CustomerService"/>
</bean>
 
<!– HTTP invoker client –>
<bean id="httpInvokerCustomerServiceProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="${url}"/>
<property name="serviceInterface"
value="com.onx.spring.remoting.services.CustomerService"/>
</bean>

Le test du client se résume à l’appel de la méthode du bean proxy.

5 Intégration de Spring
6 Mise en place d’un environnement de développement Java/Eclipse/Maven
6.1 Création d’un projet Maven/Eclipse pour Spring 2.5
a) Générer la structure du projet Maven
mvn archetype:generate -DgroupId=alti.formation.spring -DartifactId=Exemples

103
Formation  : Développement JEE avec Spring

-DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

b) Convertir le projet Maven en Eclipse


mvn eclipse:eclipse

c) Rajouter la dépendance Spring dans le pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>alti.formation.spring</groupId>
<artifactId>Exemples</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpringExamples</name>
<url>http://maven.apache.org</url>
<dependencies>
 
<!—Framework spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
 
</dependencies>
</project>

d) Créer un bean
package alti.formation.spring;
 
/**
* Spring bean
*
*/
public class HelloWorld
{
private String name;
 
public void setName(String name) {
this.name = name;
}
 
public void printHello() {
104
Formation  : Développement JEE avec Spring

System.out.println("Hello ! " + name);


}
}

e) Définir l’application context (Fichier : application-Context.xml)


<beans xmlns="http://www.springframework.org/schema/beans"
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.5.xsd">
 
<bean id="helloBean" class="alti.formation.spring.HelloWorld">
<property name="name" value="test" />
</bean>
 
</beans>

f) Exécuter l’application de test


package alti.formation.spring;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class App {
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("application-Context.xml");
 
HelloWorld obj = (HelloWorld) context.getBean("helloBean");
obj.printHello();
}
}

g)

105

Vous aimerez peut-être aussi