spring

Transcription

spring
SPRING
Master Informatique 2ème année
2011 - 2012
Michael Fortier
[email protected]
1
SPRING
●
Concepts
●
Bean
●
Injection Of Control (IoC)
●
Exemple classique
●
Aspect Oriented Programming (AOP)
●
Data Access Object (DAO)
●
●
Jdbc
●
Hibernate (*)
TP : Application complète
(gestion location de voitures)
2
SPRING
CONCEPTS
3
SPRING - Concepts
●
●
J2EE
●
Spécification
●
Manques (EJB1-2)
●
Lourdeurs
●
Difficultés (sécurité)
→ Spring pour pallier
●
Robustesse
●
Extensibilité
●
Réutilisabilité
●
→ Best practices
4
SPRING - Concepts
●
Framework de développement Java basé sur la
notion de conteneur léger
●
V3.*
●
Open Source, communauté SpringSource
●
Modulaire
"Chaque brique est indépendante"
5
SPRING - Concepts
●
Boite à tout faire
●
JSP / Servlet
●
JSF
●
Struts
●
Grails
●
RMI
●
JUnit
●
JDBC / Hibernate
●
...
→ Interopérabilité frameworks
"Conteneur léger"
Pas d'implémentation d'interface nécessaire
~ infrastructure d'un serveur
d'application JEE
6
SPRING - Concepts
●
Super fabrique d'objets qui permet de gérer :
●
Le mode transactionnel
●
L'appel/création d'EJBs
●
La persistance des objets
●
Interface Web et WebServices
7
SPRING - Concepts
●
La pile de services
8
SPRING - Concepts
●
Applications Web n-tiers
Interface
utilisateur
Métier
DAO
Moteur de servlets
Spring
Moteur de servlets
9
SPRING - Concepts
●
Applications Serveur / Client lourd
Client
lourd
Spring
Métier
Spring
remoting
DAO
Spring
Moteur de servlets
10
SPRING - Concepts
●
Applications réparties
Client
lourd
Spring
Métier
Spring
remoting
Spring
DAO
Spring
remoting
Spring
11
SPRING - Concepts
●
EJB
Client
EJB
Spring
Spring
Serveur d'applications
12
SPRING
BEAN
13
SPRING – BEAN
●
BeanFactory → Fichier de configuration
<beans>
<!-- Première fabrique-->
<bean id="produitDAO" class="product.dao.ProduitDAOImpl"></bean>
<!-- Seconde fabrique-->
<bean class="Produit">
<property name="produitDAO">
<ref bean="produitDAO"/>
</property>
</bean>
</beans>
●
Types de Bean
●
●
Singletons → création d'une instance unique à
l'initialisation (par défaut)
Prototypes → création à la demande
(lors d'un appel type : « springfactory ».getBean(«product»))
14
SPRING – BEAN
●
Propriétés → déclarer un besoin
●
Références vers autre bean (IoC)
●
Valeurs par défaut
●
Paramètres de configuration
●
Initialisations de tableaux/listes
15
SPRING – BEAN
●
Propriétés : Exemple d'initialisation
<beans>
<bean id="personne1" class="metier.Personne"
init-method="init" destroy-method="close">
<property name="nom">
<value>Bob</value>
</property>
<property name="age">
<value>40</value>
</property>
</bean>
<bean id="personne2" class="metier.Personne"
init-method="init" destroy-method="close">
<property name="nom">
<value>Roger</value>
</property>
<property name="age">
<value>20</value>
</property>
</bean>
</beans>
ApplicationContext.xml
16
SPRING – BEAN
●
Propriétés : Exemple d'Hibernate
<bean id="DerbyDatasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.apache.derby.jdbc.ClientDriver</value>
</property>
<property name="url">
<value>jdbc:derby://localhost:1527/location</value>
</property>
<property name="username">
<value>user</value>
</property>
<property name="password">
<value>mdp</value>
</property>
</bean>
<bean id="maSessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
<property name="mappingRessources">
<list>
<value>exemple.hbm.xml</value>
</list>
</property>
17
</bean>
ApplicationContext.xml
SPRING – BEAN
●
Application Java
ClassPathResource res = new ClassPathResource("applicationContext.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
ProduitServices vservices =(ProduitServices)factory.getbean("monProduitServices");
●
Application Web
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Web.xml
18
SPRING – BEAN
●
Récupérer un bean
ClassPathResource res = new ClassPathResource("applicationContext.xml");
// La fabrique SPRING est chargée, les singletons sont créés
ListableBeanFactory factory = new XmlBeanFactory(res);
// On utilise la méthode getBean en passant le nom du bean pour créer
// ou récupérer un bean déclaré dans le fichier de configuration
Personne p = (Personne)factory.getbean("personne1");
19
SPRING
INJECTION OF CONTROL
20
SPRING – IOC
●
IOC : Inversion Of Control (injection de
dépendance)
●
●
Design Pattern → casser les dépendances
Se base sur la notion d'abstraction commune
(interface java)
→ le framework qui a la charge d'injecter les
dépendances nécessaires
21
SPRING – IOC
●
IOC : Exemple simple
22
SPRING – IOC
●
IOC : Comprendre l'idée
package factory;
package product;
import factory.DAOFactory;
import product.dao.ProductDAO;
public class Product{
import product.dao.ProductDAOImpl;
import product.dao.ClientDAOImpl;
import product.dao.CommandDAOImpl;
import java.util.*;
public class DAOFactory {
private Produit dao;
private Hashtable factories;
private static DAOFactory self = null;
private long id;
private String name;
private String description;
protected DAOFactory(){
factories = new Hashtable();
factories.put("ProductDAO", new ProductDAOImpl());
factories.put("ClientDAO", new ClientDAOImpl());
factories.put("CommandDAO", new CommandDAOImpl());
}
public Product(){
Dao =
(Produit)DAOFactory.getFactory("ProductDAO");
}
public static Object getFactory(String factoryName) throws NullPointerException {
return DAOFactory.self().get(factoryName);
}
public String getName(){return name;}
}
//etc
protected Object get(String factoryName) throws NullPointerException {
return factories.get(factoryName);
}
Appel à la classe DAOFactory
Implémentations des différents
DAO déclarés en dur
}
public static synchronized DAOFactory self(){
if(self == null){
self = new DAOFactory();
}
return self;
}
23
SPRING – IOC
●
IOC : Comprendre l'idée
●
Problèmes :
- Comment tester quand les classes implémentant les DAO ne sont
pas développées ?
- Faire fonctionner des classes DAO différentes suivant le contexte
d'exécution (développement, production...)
24
SPRING – IOC
●
IOC : Comprendre l'idée
●
Solution
package product;
import factory.DAOFactory;
import product.dao.ProductDAO;
public class Product{
private ProductDAO dao;
private long id;
private String name;
private String description;
public void setProductDAO(ProductDAO dao){
this.dao = dao;
}
public String getName(){return name;}
//etc
}
Fichier de configuration Spring :
<beans>
<!-- Première fabrique-->
<bean id="productDAO"
class="product.dao.ProductDAOImpl"></bean>
<!-- Seconde fabrique-->
<bean class="product.Product">
<property name="productDAO">
<ref bean="productDAO"/>
</property>
</bean>
</beans>
25
SPRING – IOC
●
3 types d'injection
●
par constructeur
Object construitComposant(String pNom){
Class c=rechercheLaClassQuiImplemente(pNom) ;
String[] dep= rechercheLesDependance(pNom) ;
Params[] parametresDeConstructeur;
Pour chaque element (composant) de dep
Faire
Object o= construitComposant(composant) ;
Rajouter o à la liste de parametresDeConstructeur ;
Fin Faire
construireClasse( c, parametresDeConstructeur)
}
26
SPRING – IOC
●
3 types d'injection
●
par mutateurs (setter)
Object construitComposant(String pNom){
Class c=rechercheLaClassQuiImplemente(pNom) ;
Object composant=new c() ;
String[] dep= rechercheLesDependance(pNom) ;
Params[] parametresDeConstructeur;
Pour chaque element (composant) de dep
Faire
Object o= construitComposant(composant) ;
composant.setNomMembre(o) ;
Fin Faire
}
27
SPRING – IOC
●
3 types d'injection
●
interface
Object construitComposant(String pNom){
Class c=rechercheLaClassQuiImplemente(pNom) ;
Object composant=new c() ;
String[] dep= rechercheLesDependance(pNom) ;
Params[] parametresDeConstructeur;
Pour chaque element (composant) de dep
Faire
Object o= construitComposant(composant) ;
composant.méthodeInjection(o) ;
Fin Faire
}
public interface IInjectMethode{
public void méthodeInjection(Object o) ;
}
28
SPRING
EXEMPLE CLASSIQUE
29
SPRING – EXEMPLE CLASSIQUE
●
Le cas d'une gestion de stock d'articles
public class Stock{
// Déduis une quantité du stock d'articles
void sortArticleDuStock(String pArticleId, int quantite, java.sql.Connection pConn){
try{
String sql ="update Articles a set a.quantite=a.quantite-" +
quantite + " where a.articleId='" + pArticleId + "'";
Statement statement=pConn.createStatement();
statement.executeStatement(sql);
} catch(Exception e){
e.printStackTrace();
}finally{
if(statement != null){
try{
statement.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
}
}
30
}
SPRING – EXEMPLE CLASSIQUE
●
Problèmes :
●
Les tests ne sont pas effectués (article inexistant,
quantité négative...)
→ code peu résistant
●
Maintenabilité ?
●
Testabilité ?
31
SPRING – EXEMPLE CLASSIQUE
●
Améliorations :
public class Stock{
void sortArticleDuStock(String pArticleId, int pQty, java.sql.Connection pConn)
throws ArticleNotFoundExeception, QtyNegativeException(){
try{
if(pQty<0){ thrown new QtyNegativeException(); }
sql ="select 'x' from Articles a where a.articleId='" + pArticleId + "'";
Statement statement=pConn.createStatement();
Resultset resultSet=statement.executeQuery(sql);
if(resultSet==null ¦¦ !resultSet.next()){
thrown new ArticleNotFoundException();
}
String sql ="update Articles a set a.quantite=a.quantite-" + quantite + " where a.articleId='" +
pArticleId + "'";
statement=pConn.createStatement();
statement.executeStatement(sql);
} catch(SQLException e){ e.printStackTrace();
} finally{
if(statement != null){
Try{ statement.close();
}catch(SQLException ex){ ex.printStackTrace();}
}
}
}
}
32
SPRING – EXEMPLE CLASSIQUE
●
Spring → découpler les couches métiers et
accès aux données
// Interface pour gérer la couche métier
public interface IStockBusiness{
void sortArticleDuStock(String pArticleId, int quantite)
throws ArticleNotFoundExeception, QtyNegativeException();
}
// Interface pour gérer la couche d'accès aux données
public interface IStockDao{
void sortArticleDuStock(String pArticleId, int quantite);
boolean ArticleExist(String pArticleId);
}
33
SPRING – EXEMPLE CLASSIQUE
// Implémentation de la classe d'accès aux données
class StockDAO implements IStockDao extend JdbcDaoSupport{
DataSource mDataSource;
public setDataSource(DataSource pDataSource){
mDataSource=pDataSource;
}
boolean articleExist(String pArticleId){
String sql = "select count(*) from Articles a where a.articleId='" + pArticleId + "'";
int count = jt.queryForInt(sql);
return count > 0 ? true : false;
}
}
void sortArticleDuStock(String pArticleId, int pQty){
String sql = "update Articles a set a.quantite=a.quantite-" + quantite + " where a.articleId=' +
pArticleId + "'";
getJdbcTemplate().execute(sql);
}
34
SPRING – EXEMPLE CLASSIQUE
// Implémentation de la classe métier
class StockBusiness implements IStockBusiness{
IStockDao mDao;
public setDao(IStockDao pDao){
mDao=pDao;
}
void sortArticleDuStock(String pArticleId, int quantite) throws ArticleNotFoundException,
QtyNegativeException(){
if(quantite<0){
thrown new QtyNegativeException();
}
}
if(!mDao.articleExist(pArticleId)){
thrown new ArticleNotFoundException();
}
mDao.sortArticleDuStock();
boolean articleExist(String pArticleId){
return mDao.articleExist(pArticleId);
}
}
35
SPRING – EXEMPLE CLASSIQUE
<?xml version="1.0" encoding="UTF-8"?>
<!-- Fichier de configuration de Spring -->
<beans>
<bean id="prodDataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"><value>org.postgresql.Driver</value></property>
<property name="url"><value>jdbc:postgresql://localhost:5432/prod</value></property>
<property name="username"><value>prod</value></property>
<property name="password"><value>toto</value></property>
</bean>
<bean id="stockDao" class="StockDao">
<property name="dataSource">
<ref local="prodDataSource"/>
</property>
</bean>
<bean id="stockBusiness" class="StockBusiness">
<property name="dao">
<ref local="stockDao"/>
</property>
</bean>
</beans>
36
SPRING
ASPECT ORIENTED
PROGRAMMING
37
SPRING – AOP
●
AOP : Aspect Oriented Programming
(programmation par aspect)
Implications :
•
•
•
•
Enchevêtrement du code
Faible réutilisabilité
Qualité plus basse due à la complexité
Difficulté à faire évoluer
Préoccupations mélangées
38
SPRING – AOP
●
AOP : Aspect Oriented Programming
(programmation par aspect)
Solutions :
•
•
•
Préoccupations séparées
Décomposer en aspect
Programmer la partie métier
Recomposer les aspects
Ajouter du comportement sans
modification de code
39
SPRING – AOP
●
Intérêt de Spring
●
Découplage des modules
–
–
–
–
●
Maintenance accrue
Meilleure réutilisation
Gain de productivité
Qualité du code améliorée
Code non intrusif
40
SPRING – AOP
●
2 types de programmations :
●
Statique : au début ou à la fin
●
Dynamique : au moment de l'exécution (plus lent)
→ reconfiguration sans compilation
41
SPRING – AOP
●
Vocabulaire :
●
Point de jonction (Joinpoint)
●
Point d'actions (pointcut)
●
Conseil / greffon (advice)
●
Aspect
●
Trammeur / tisseur (Weaver)
42
SPRING – AOP
●
Exemple : gestion des journaux
package metier;
public class Personne {
// Affichage des informations de l'individu
public String toString2() {
String s="nom=[" + this.nom + "], age=[" + this.age + "]";
System.out.println(s);
return s;
}
}
43
SPRING – AOP
package test;
import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.MessageService;
public class PersonneTest extends TestCase {
}
public void testPersonne() {
ApplicationContext context = new ClassPathXmlApplicationContext( new String[]
{"applicationContext.xml"} );
Personne p = (Personne) context.getBean("personne");
p.toString2();
}
-> nom=[Bob], age=[40]
44
SPRING – AOP
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean name="messageService" class="service.MessageService" />
<!-Debut de la configuration AOP -->
<bean id="monLogger" class="aop.MonLogger"/>
<aop:config>
<aop:pointcut id="servicePointcut" expression="execution(* service.MessageService.*(..))"/>
<aop:aspect ref="monLogger">
<aop:before method="logDebutMethode" pointcut-ref="servicePointcut"/>
<aop:after-returning method="logFinMethode" returning="result"
pointcut-ref="servicePointcut"/>
<aop:around method="injectAround" pointcut-ref="servicePointcut" />
</aop:aspect>
</aop:config >
<!-Fin de la configuration AOP -->
45
</beans>
ApplicationContext.xml
SPRING – AOP
package aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.JoinPoint.StaticPart;
public class MonLogger {
// Cette méthode est appelée à chaque fois (et avant) qu'une méthode du package service
//est interceptée
public void logMethodEntry(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
// Nom de la méthode interceptée
String name = joinPoint.getSignature().toLongString();
StringBuffer sb = new StringBuffer(name + " called with: [");
// Liste des valeurs des arguments reçus par la méthode
for(int i = 0; i < args.length; i++) {
Object o = args[i];
sb.append("'"+o+"'");
sb.append((i == args.length - 1) ? "" : ", ");
}
sb.append("]");
}
System.out.println(sb);
46
SPRING – AOP
// … suite
// Cette méthode est appelée à chaque fois (et après) qu'une méthode du package service est
// interceptée. Elle reçoit en argument 'result' qui est le retour de la méthode interceptée
public void logMethodExit(StaticPart staticPart, Object result) {
// Nom de la méthode interceptée
String name = staticPart.getSignature().toLongString();
}
System.out.println(name + " returning: [" + result + "]");
// Cette méthode est appelée avant ET après qu'une méthode du package service est
// interceptée.
public Object injectAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("INJECT BEFORE!");
// Execution de la méthode
Object retVal = null;
try { retVal = pjp.proceed();
} catch (Exception e) {}
}
}
System.out.println("INJECT AFTER!");
return retVal;
47
SPRING
DATA ACCESS OBJECT
48
SPRING - DAO
●
Design Pattern DAO : principe général
49
SPRING - DAO
●
Design Pattern DAO : structure générale
utilise
Obtient
Modifie
encapsule
Créé / utilise
Création d'un objet DAO par classe métier (non par objet)
50
SPRING - DAO
●
Principes pour Spring :
●
Faire une abstraction par rapport à la méthode
d’accès à la base de données (framework de
mapping, jdbc …)
●
Offrir un système de management des transactions
●
Offrir un système d’accès aux données
●
Offrir une hiérarchie d’exceptions génériques.
51
SPRING - DAO
Spring
Invariable
- Ouvrir et fermer
les connexions
- Initialiser les ressources
Template
Spécifique
- Exécuter une requête
- Récupérer le résultat
Callback
52
SPRING - DAO
53
SPRING - DAO
54
SPRING - JDBCTemplate
●
Intérêts :
●
Définir les paramètres de connexion
●
Ouvrir la connexion
●
Spécifier les statements
●
Préparer et exécuter les statements
●
Établir la boucle permettant de parcourir les résultats (si il y en a)
●
Faire le travail pour chaque itération
●
Traiter n'importe quelle exception
●
Se charger des transactions
●
Fermer la connexion
55
SPRING - JDBCTemplate
●
Configuration dans Spring
<beans>
...
<bean id="derbyDao" class="dao.DerbyDao">
<property name="datasource" ref="DerbyDatasource" />
</bean>
<bean id="DerbyDatasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.apache.derby.jdbc.ClientDriver</value>
</property>
<property name="url">
<value>jdbc:derby://localhost:1527/location</value>
</property>
<property name="username">
<value>user</value>
</property>
<property name="password">
<value>mdp</value>
</property>
</bean>
…
56
</beans>
SPRING - JDBCTemplate
●
Exemple d'utilisation
public class DerbyDAO {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public int getCount() {
return this.jdbcTemplate.queryForInt("select count(*) from location.personne");
}
public void insertPersonne(Personne p) {
this.jdbcTemplate.update("insert into location.personne (nom,age) values (?,?)",
new Object[]{p.getNom(),p.getAge()});
}
//...
57
SPRING - JDBCTemplate
//... suite
public List getList() {
return getJdbcTemplate().query("select * from location.personne",
new BeanPropertyRowMapper(Personne.class));
}
}
58
SPRING - Hibernate
●
Rôles / intérêts :
●
Gérer la persistance d'objets Java
●
Offrir des outils de mapping Objet / Relationnel
●
Lazy loading
●
Abstraction de la couche JDBC (HQL...)
59
SPRING – Hibernate
●
Configuration complète dans Spring
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@localhost:1521:test</value>
</property>
<property name="username">
<value>usr</value>
</property>
<property name="password">
<value>pwd</value>
</property>
</bean>
<bean id="sessionFactoryBean"
class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
60
...
SPRING – Hibernate
<property name="dataSource">
<ref bean="dataSource" /></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">net.sf.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">false</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>mapping/Employee.hbm.xml</value>
<value>mapping/Codes.hbm.xml</value>
</list>
</property>
</bean>
<bean id="basicDataDao" class="impl.BasicDataDaoImpl">
<property name="sessionFactory">
<ref bean="sessionFactoryBean" />
</property>
</bean>
61
SPRING – Hibernate
public class BasicDataDaoImpl extends HibernateDaoSupport
implements IBasicDataDao {
/**
* Effacement d'un individu
*/
public void deleteIndividu(String pIndividuId) {
// Recherche de l'existence de l'individu
List l=getHibernateTemplate().find("from individu e where e.Id='"+pIndividuId+"'");
if(l.size()>0){
Individu ret=(Individu)l.get(0);
// Suppression
getHibernateTemplate().delete(ret);
}
}
}
62
SPRING
●
Conclusion :
●
●
●
●
Très ouvert et ne limite pas les comportements : pour un même
problème, il existe plusieurs solutions → déroutant
Spring facilite l'intégration et l'utilisation de librairies tierces, mais
la connaissance et la compréhension de ces librairie restent
nécessaires.
Le comportement générique n'est pas forcément adapté aux
besoins.
Spring est structurant et améliore de façon significative la
productivité et la maintenabilité des applications.
Il n'y a pas là d'invention géniale mais plutôt un ensemble
cohérent qui, bien que puissant, est simple et relativement intuitif
à mettre en œuvre.
63
SPRING
●
Bibliographie :
●
●
http://www.springframework.org/
http://java.sun.com/blueprints/corej2eepatterns/Patt
erns/DataAccessObject.html
●
Spring par la pratique, Eyrolles, 2006
●
Spring par l'exemple, PEARSSON, 2008
●
http://www.martinfowler.com/articles/injection.html
64