GMIN30F Réutilisation / Composants Intervenant : André Morassut Informations légales Ce document est la propriété exclusive de Berger-Levrault, toute reproduction même partielle est interdite sans l’autorisation écrite des services idoines de Berger-Levrault. Le logo Berger-Levrault est la propriété exclusive de BergerLevrault S.A. Les autres images de cette présentation sont issues de commons.wikimedia.org Structure 1. Contexte industriel Le contexte « industriel » la perception des notions Convergences et motifs : réutilisabilité et composants Un cas d’expérience : le CORE WEB2 2. Réutilisation et composants – En pratique Réutilisation « passive » et « active » Composants internes et externes 3. Pratiques actuelles Présentation d’outils représentatifs de l’outillage actuel favorisé par les éditeurs de logiciel SECONDE PARTIE Projet de développement – Réalisation d’un projet JAVA EE+MAVEN+SPRING – Serveur REST sur base JPA – Grandes étapes de mise en place : • Partie 1 : – – – – Mise en place du projet Branchement de MAVEN Mise en place de SPRING Définition d’un service REST « helloworld » • Partie 2 : – Mise en place de JPA – Création des entités métier + DAO + services – Branchement des services REST Travaux de programmation Partie 1 - Webapplication Partie 1 - Webapplication – Focus sur les briques manipulées : • MAVEN : voir partie 1 du cours • SPRING : « boîte à outils » en lien avec JAVA EE • REST : approche architecturale consistant en une ensemble coordonné de contraintes sur l’utilisation d’abstractions (structuration des informations, composants, connecteurs, …) de l’architecture du « world wide web » • Serveur JAVA EE : Serveur WEB intégrant des logiques de traitement des cycles de vie d’aspects normés JAVA EE. SPRING SPRING – Synthétiquement, SPRING présente des alternatives et des implémentations de normes JAVA EE – SPRING présente de multiple facettes : • • • • • IoC (Injection de dépendances) JPA & transactions : DsL, helpers, etc. Web application : lifecycle, servlets, etc. Security Autres: – NoSQL, Social, Cloud, Batch processing, LDAP, Mobile, etc. REST REST – REST = REpresentational State Transfer – Créé en 2000, REST s’impose largement en entreprise ces dernières années – REST apporte: • • • • Un ensemble de contraintes architecturales Une approche d’abstraction Une ouverture technologique Une forte orientation composant – Pour ces raisons REST est particulièrement adapté à une vision architecturale modulaire Voyons les contraintes en détail REST – Contraintes (1/4) – Contraintes architecturales: • • • • Client/serveur Sans état (Stateless) Cachable Système en couches – Approche d’abstraction Implémentation WWW : • • • • Utilisation des « verbes » HTTP Utilisation d’un format de données ouvert : JSON, XML Utilisation des URI Utilisation des Hyperliens REST – Contraintes (2/4) – Ouverture technologique • REST peut être implémenté dans toutes les technologies permettant des composantes sous-jacentes (http, json, xml, etc.) • Les notions à implémenter : – Ressource = élément d’une API REST, c’est une opération unitaire – Représentation = donnée structurée représentant une notion manipulée par une interface REST, en entrée ou sortie – Message = communication client vers serveur ou inversement, pouvant contenir une ou plusieurs représentations par exemple – « Hypermedia state » = opérations disponibles sur un serveur REST à un instant donné REST – Contraintes (3/4) – Orientation composant : REST propose une uniformisation des interfaces (contrats) autour de certaines contraintes • Identification des ressources & séparation ressource/représentation Chaque ressource est identifiable par requête (utilisation des URI dans une implémentation www) et les représentations manipulées sont conceptuellement séparée des ressources (ainsi, un serveur peut retourner une information en JSON ou XML, celle-ci sera une projection de la représentation interne du serveur qui peut être éventuellement plus riche.) • Les représentations permettent la manipulation des ressources Les représentations retournées par un serveur en réponse à une requête sont suffisantes à un client donné pour qu’il puisse modifier ou supprimer les éléments correspondants REST – Contraintes (4/4) – Orientation composant : REST propose une uniformisation des interfaces (contrats) autour de certaines contraintes • Messages auto descriptifs Chaque message contient les informations suffisantes pour permettre à un client de savoir comment les traiter. En pratique, c’est l’inclusions d’informations comme : encodage (utf-8, etc.), structuration (xml, json, etc.), gestion de la mise en cache, etc. • HATEOAS : « hypermedia as the engine of application state » Une API REST présentée par un serveur peut être vue comme une machine à état. Un client peut uniquement déclencher des transitions d’états à travers les opérations mises à disposition à un instant donné par le serveur. Serveur JAVA EE Serveur JAVA EE – Un serveur JAVA EE (ex: Glassfish, JBOSS AS, etc.) est un serveur d’application implémentant un ensemble de normes JAVA EE. – À travers un système de certification, ORACLE estampille un serveur comme « JAVA EE » s’il implémente correctement un ensemble de normes jugées indispensables – Quelques serveurs JAVA EE: • EE 7 : Glassfish 4, RedHat WildFly 8, … • EE 6 : JBOSS AS7, Apache Geronimo 3, Glassfish 3, Websphere 8, … Serveur JAVA EE – Un serveur JAVA EE propose typiquement plusieurs moyens de configuration • Console dédiée • JMX connectors – Un serveur JAVA EE permet la gestion des versions des modules qu’il intègre, indépendamment des applications – Nous verrons l’intérêt d’un serveur d’application à travers la gestion de deux aspects : • Injection de dépendances • Gestion des transactions Travaux de programmation Partie 2 - Webapplication Partie 2 - Webapplication – Focus sur les notions & briques manipulées : • Modalités architecturales JAVA EE – Applications en couche – DAO & « Active record » • En lien avec les serveurs d’application – Inversion de contrôle : détail de cette notion – Gestion des transactions : détail de cette notion • JPA : norme JAVA EE de gestion de la persistance • Aspects connexes : logging, Unit tests Modalités architecturales diapo 21 Modalités architecturales • Les architectures autour de JAVA EE convergent autour de quelques point essentiels – Approche en couche • Séparation des responsabilités • Entités métiers & services essentiellement – Stateless (versus stateful) – Approche de persistance • Par DAO • Par « active record » diapo 22 Modalités architecturales Détaillons les deux approches de gestion de l’isolation du code de persistance: - Approche « Data Access Object » - Les DAO sont des objets dédiés à la gestion de la persistance - Les objets métiers n’ont aucune « intelligence métier », ce sont de simple conteneurs de données - Les DAO intègrent une partie de l’intelligence métier (une couche service est souvent employée pour séparer l’orchestration de la persistance) - Généralement, on met en place un objet DAO par objet métier avec extension d’une super classe regroupant les implémentations par défaut diapo 23 Modalités architecturales Détaillons les deux approches de gestion de l’isolation du code de persistance: - Approche « Active Record » - Contrairement à l’approche DAO, le code de persistance est intégré aux objets métier - Les objets métiers contiennent l’intelligence du métier - Parfois, une couche service est mise en place pour des raisons d’orchestration. - Par exemple, on peut avoir besoin de coordonner des objets Personne, Adresse, Ville, etc. pour réaliser une fonctionnalité métier d’enregistrement d’une nouvelle personne. diapo 24 Architecture Web, Active record JAVA EE Container ou Spring Client SGBDs Oracle / sql server / … diapo 25 Objets métier Hibernate (Service) Architecture Web, approche DAO JAVA EE Container ou Spring Client Service DAO Objets métier diapo 26 SGBDs Oracle / sql server / … Hibernate Modalités architecturales Comparons les deux approches de gestion de l’isolation du code de persistance: - Approche « Data Access Object » Avantages Inconvénients -Séparation des responsabilités - Permet de factoriser du code par la superclasse de DAO - Simplification des tests par « mock » ou « bouchonnage » - Permet de remplacer une implémentation de manière ciblée - Adapté à des projets de taille importante -Le coût réel des appels en base de données est masqué - Prolifération des DAO si le nombre des entités métier est élevé - Il faut être vigilant pour ne pas introduire des aspects métiers dans les DAO L’approche DAO est particulièrement adaptée aux domaines métiers multi-sujets. diapoétendus, 27 - Modalités architecturales Comparons les deux approches de gestion de l’isolation du code de persistance: - Approche « Active record » Avantages Inconvénients -Simplicité -Réduction du nombre de classes - Cohérent avec l’approche objet : les entités métiers ne sont pas de simples conteneurs de donnée - le domaine métier est peu malléable : si un objet donné doit être utilisé dans plusieurs contextes différents, son code s’en trouvera très complexifié - lourdeur des refactorings -Difficultés pour les tests L’approche Active record est intéressante quand le domaine métier est réduit et traite d’un objectif unique diapo 28 Modalités architecturales Ces deux approches sont très généralement mises en place de manière STATELESS. Ainsi, les services ne conservent aucun état et ne connaissent pas les sessions de travail des clients. Cela implique que chaque opération exposée par le serveur doit : - permettre d’aller d’un état cohérent du domaine métier à un autre état cohérent - ne pas requérir d’être orchestrée dans un ordre particulier En réalité, l’aspect STATELESS de l’architecture rapproche l’API exposée par le serveur aux clients de REST. diapo 29 JAVA EE - Transactions & IOC Injection de dépendances (1/8) IoC signifie « Inversion of Control » L’inversion de contrôle est permise par l’injection de dépendances Principe de l’inversion des dépendances, permet : – Suivre les évolutions techniques tout en épargnant le code métier – Réflexion sur couplage fort versus couplage faible par interfaces. Un bon design objet est plus important que les technologies sous-jacentes. Tout code doit être facilement testable. diapo 31 Différentes dépendances (2/8) diapo 32 A B A << I >> A B A utilise B A implémente une interface I A hérite de B IOC - Conséquences (3/8) • Les dépendances ne permettent pas : – D’installer A sans installer B • Donc de réutiliser A sans réutiliser B – Une modification de B • Peut entraîner une modification de A • Une recompilation de A – Il y a perte de réutilisation et de modularité A diapo 33 B IOC - Conséquences (4/8) • Objectifs : Eviter – Rigidité • Application difficile à modifier car chaque changement affecte d'autres parties du logiciel – Fragilité • Une modification entraîne des effets de bords : BUG – Immobilité • Difficulté de reprendre une partie de l'application car elle ne peut pas être indépendante des autres parties A diapo 34 B IOC - Direction (5/8) Classe A Classe B Classe A ou Peut-on choisir le sens d’une dépendance ? diapo 35 Classe B Inversion de dépendances (6/8) Situation de départ Classe A Classe B Ajout d’une interface Classe A Interface I Classe B implémente diapo 36 Injection de dépendance (7/8) Problématique initiale : – pouvoir remplacer l’implémentation utilisée par un composant de manière simple – L’injection a pour base la notion d’interface : le composant « utilisateur » se base sur un « contrat » Pattern : ClasseA ClasseB IClasseB implémente setIClasseA() Cible de l’injection diapo 37 Injection de dépendances (8/8) – Dans le cadre d’un serveur d’application : • Via un conteneur JAVA EE (serveur JAVA EE), nous allons pouvoir laisser celui-ci gérer les injections • Ainsi, selon la charge, les éléments de paramétrage, etc. le serveur va décider d’instancier, réutiliser, mettre en cache, etc. les ressources déclarées en injection • D’autres ressources peuvent être injectées : – Data sources – Règles de sécurité – Etc. • Les serveurs peuvent être configurés pour fonctionner en coopération : gestion de la charge, réplications, etc. Un tel serveur représente une composante importante d’une architecture industrielle, rendant des services qui sont de fait découplés des applications métier (séparation des responsabilités) Gestion des transactions Notion de transaction : Une transaction permet d’associer un ensemble d’opérations dans une session de travail. Si les exécutions de toutes les opérations se terminent correctement la transaction aboutie Si une des opérations ne se termine pas correctement, la transaction échoue Un exemple • La réservation d’un billet de spectacle 4 opérations OK Réserver billet 1- Consultation des places disponibles 2- Réservation de la place 3- Réception du paiement 4- Émission du ticket de réservation 1 opération KO diapo 40 Propriétés ACID (1/2) • Propriétés fondamentales d’une transaction Atomic (Atomicité) Les opérations qui constituent une transaction forment une unité indivisible : soit l’ensemble des opérations est mené à terme, soit aucune opération n’est effectuée. Consistent (Cohérence) La base passe d’un état initial cohérent à un état final cohérent, dans le respect des règles d’intégrités référentielles définies sur la base de données. diapo 41 Propriétés ACID (2/2) Isolated (Isolation) Les mises à jour effectuées au cours de l’exécution d’une transaction restent invisibles aux autres transactions. Durable (Durabilité) Le résultat de la transaction est persisté dans le système, même après l’arrêt de celui-ci. diapo 42 JPA, Spring & transactions Les EJBs (Enterprise Java Bean), comme SPRING, apportent un support pour les transactions programmatiques et déclaratives La gestion des transactions des EJBs peut être couplée avec une implémentation de JTA (Java Transaction API) Spring n’est pas obligatoirement couplé à JTA diapo 43 Déclarative vs Programmatique La gestion programmatique des transactions apporte un meilleur contrôle et une granularité plus fine et plus proche du code La gestion déclarative des transactions permet de garder la logique transactionnelle en dehors de la logique métier diapo 44 Transactions programmatiques Correspond à la gestion des transactions de manière explicite par des instructions spécifiques dans le code métier traitant de la persistance Les transactions sont gérées explicitement par le développeur Exemple : EntityManagerFactory emf = Persistence.createEntityManagerFactory("tp"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); em.persist(newInstance); em.getTransaction().commit(); em.close(); emf.close(); diapo 45 Transactions déclaratives Spring comme JAVA EE permet d’utiliser la fonctionnalité des transactions déclaratives sur les POJOs Les transactions déclaratives : Réalisées grâce à une approche AOP Une transaction peut être vue comme un aspect qui intercepte une méthode (Around Advice) Le développeur spécifie par métadonnées (hier xml, aujourd’hui annotations) les caractéristiques du contexte transactionnel nécessaire à chaque méthode Exemple : @Transactional(propagation = Propagation.SUPPORTS, readOnly = true) public void processCode(final String pCode) { // instructions... } diapo 46 Les attributs transactionnels • Les transactions déclaratives sont configurées par des attributs transactionnels • Ils définissent la politique et les comportements transactionnels des méthodes – sur les propagations des transactions – sur les niveaux d’isolation – Et aussi : • sur les optimisations Read-only • sur les Timeouts diapo 47 Propagation des transactions (1/8) Sept modes de propagation des transactions sont disponibles : MANDATORY NESTED NEVER NOT_SUPPORTED REQUIRED REQUIRES_NEW SUPPORTS diapo 48 Propagation des transactions (2/8) • PROPAGATION_MANDATORY – Indique que la méthode doit s’exécuter dans une transaction, une exception est lancée si aucune transaction n’est définie Client Service sans TX TX1 X DAO Exception TX1 PROPAGATION_MANDATORY diapo 49 Propagation des transactions (3/8) • PROPAGATION_NESTED – Indique que la méthode doit s’exécuter dans une transaction imbriquée si une transaction existante est en cours. La transaction imbriquée peut avoir un Commit ou un RollBack indépendant de la transaction existante. Si aucune transaction existante, se comporte comme PROPAGATION_REQUIRED Client Service sans TX DAO TX1 TX1 TX2 PROPAGATION_NESTED diapo 50 Propagation des transactions (4/8) • PROPAGATION_NEVER – Indique que la méthode ne doit pas s’exécuter dans un contexte transactionnel, une exception est lancée si une transaction est en cours Client Service sans TX TX1 sans TX X Exception PROPAGATION_NEVER diapo 51 DAO Propagation des transactions (5/8) • PROPAGATION_NOT_SUPPORTED – Indique que la méthode ne doit pas s’exécuter dans un contexte transactionnel. Si une transaction est en cours, celle ci est suspendue pour la durée d’exécution de la méthode Client Service DAO sans TX sans TX TX1 sans TX PROPAGATION_NOT_SUPPORTED diapo 52 Propagation des transactions (6/8) • PROPAGATION_REQUIRED – Indique que la méthode doit s’exécuter dans un contexte transactionnel. Si une transaction est en cours, celle ci est utilisée, sinon une nouvelle transaction est initiée. Client Service sans TX TX1 TX1 TX1 PROPAGATION_REQUIRED diapo 53 DAO Propagation des transactions (7/8) • PROPAGATION_REQUIRES_NEW – Indique que la méthode doit s’exécuter dans son propre contexte transactionnel. Si une transaction est en cours, une nouvelle transaction est initiée et la transaction existante est suspendue pour la durée d’exécution de la méthode Client Service DAO sans TX TX1 TX1 TX2 PROPAGATION_REQUIRES_NEW diapo 54 Propagation des transactions (8/8) • PROPAGATION_SUPPORTS – Indique que la méthode n’exige pas un contexte transactionnel, mais peut s’exécuter dans une transaction si elle existe Client Service sans TX DAO sans TX TX1 TX1 PROPAGATION_SUPPORTS diapo 55 L’isolation des transactions (1/2) • Dans une application d’entreprise, les transactions s’exécutent de manière concurrente sur des données communes • La concurrence des actions peut mener aux problèmes suivants : • Dirty read – Lectures pouvant se produire sur des données non encore "comitées" par une autre transaction. En cas de Rollback les données obtenues sont invalides • Nonrepeatable read – Se dit d’une transaction qui exécute une même requête plusieurs fois et récupère des données pouvant être différentes. La différence étant due à une autre transaction concurrente mettant ces données à jour diapo 56 L’isolation des transactions (2/2) • Phantom reads – Se produit lorsqu’une une transaction lit plusieurs lignes, pendant qu’une autre transaction concurrente insert des lignes. Sur une nouvelle requête des nouvelles lignes peuvent apparaitre • Dans une situation idéale, les transactions concurrentes sont complètement isolées les une des autres, pour éviter les problèmes cités précédemment • Mais l’isolation parfaite affecte les performances – Lock des lignes et parfois des tables! – Le lock agressif oblige les transactions à s’attendre entre elles • Dans certains cas, il peut être intéressant de relâcher les niveaux d’isolation. diapo 57 Exemples de niveaux d’isolation • • • • • ISOLATION_DEFAULT – Utilise le niveau d’isolation par défaut de la base de données. ISOLATION_READ_UNCOMMITTED – Permet de lire des données d’autres transactions concurrentes non encore "comitées". Peut engendrer des dirty reads, phantom reads et nonrepeatable reads. ISOLATION_ READ_COMMITTED – Permet de lire des données d’autres transactions concurrentes uniquement "comitées". Évite les dirty reads mais pas les phantom reads et nonrepeatable reads. ISOLATION_REPEATABLE_READ – Les lectures multiples sur un même champ produisent les mêmes résultats. Évite les dirty reads et les nonrepeatable reads mais pas les phantom reads. ISOLATION _SERIALIZABLE – Niveau d’isolation ACID complet, évite les dirty reads, les nonrepeatable reads et les phantom reads. C’est le moins performant des niveaux d’isolation (mis en œuvre de locks plus important). Note : tous ces niveaux d’isolation ne sont pas supportés par toutes les sources de données. diapo 58 JAVA EE : JPA JAVA EE : JPA – JPA : Java Persistence API – À l’origine, JPA est une API visant à normaliser la gestion de la persistance dans une application JAVA EE face à une base relationnelle. – JPA évolue pour intégrer les notions de persistances non-relationnelles (noSQL, etc.) et est de plus en plus couplé à la problématique de la validation (« Bean validation », JSR-303) JAVA EE : JPA – Historique : • JPA 1.0 : – En 2006 via JSR-220 – Périmètre initial • JPA 2.0 : – En 2009 via JSR-317 – Améliorations notables : Criteria, Validation, Mapping extensions, … • JPA 2.1 : – En 2013 via JSR-338 – Améliorations notables : Custom converters, entity graphs, stored procedures, … JAVA EE : JPA • JAVA JPA couvre essentiellement trois domaines – API de persistance : • dans le package javax.persistence, nous y trouvons notamment des « entity manager », « transaction manager », etc. Cette API permet de cadrer le périmètre de gestion des requêtes, transactions, erreurs courantes, … via des interfaces (contrat). • Principales notions : – EntityManagerFactory : usine à EntityManager – EntityManager : Facade d’accès à une session de persistance – EntityTransaction : Interface de manipulation des transactions (commit, rollback, …) JAVA EE : JPA • JAVA JPA couvre essentiellement trois domaines – API de persistance : • Principales notions : – Query : Interface de gestion d’une requête donnée (exécution, mise à jour, etc.) – Criteria : Interface alternative de gestion d’une requête donnée – FlushMode : Mode de réalisation des opérations en base de données • La « session de persistance » est une notion centrale JAVA EE : JPA • JAVA JPA couvre essentiellement trois domaines – JPQL • Langage de requêtage très proche de SQL : permet de manipuler directement les éléments objets (classes, attributs) avec les mots clef SELECT/FROM/WHERE/… • Issu de HQL (langage spécifique HIBERNATE) • Fournit des fonctions scalaires indépendantes des moteurs de base de données – Métadonnées Objet/Relationnel • Annotations permettant de « décorer » les entités persistances • Permet de spécifier le mapping O/R : @Entity, @Table, @Column, @ManyToOne, @ManyToMany JAVA EE : JPA • JAVA EE fournit le cadre (contrats) uniquement via son JDK. Les implémentations peuvent être fournies par d’autres éditeurs. Dans le cas de JPA, ces implémentations sont appelées « JPA PROVIDER » • Exemples : – Hibernate – TopLink – OpenJPA –… JAVA EE : JPA • Quel que soit l’implémentation retenue pour un projet, le JPA PROVIDER manipulera la notion de « session de persistance » • Cette notion permet de connaître, à un instant donné de l’exécution d’un service défini en utilisant JPA, quels sont les objets qui seront affectés par la persistance • Le JPA PROVIDER permet une abstraction de la source de données. C’est lui qui choisit notamment quand et comment son modèle mémoire est synchronisé avec la base de données Session de persistance (1/3) Un JPA Provider tel que Hibernate ne manipule pas directement les POJOs, mais des proxys obtenus par introspection. Les proxys contiennent les propriétés du POJO, ainsi que des informations utilisées par le JPA PROVIDER diapo 67 Session de persistance (2/3) La session de persistance est un cache au niveau transactionnel. C'est elle qui contient les proxys. Son cycle de vie est géré par le container (Server JAVA EE typiquement), qui peut se charger aussi de créer la transaction et de la committer ou roll-backer. Un objet en session est persistant : objet qui a été récupéré ou sauvé en base. Un objet qui n'est pas en session est transient. Avant de créer une relation entre un objet persistant et un objet transient, il est nécessaire de rendre ce dernier persistant. diapo 68 Session de persistance (3/3) Cycle de vie d’un entity JPA diapo 69 GMIN30F Réutilisation / Composants Intervenant : André Morassut