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