Maven
Présentation
Pourquoi Maven ?
Actuellement la majorité des projets Java/JEE utilisent Maven. Est-ce une mode, un besoin, une geekerie ?
Maven répond à un besoin, c’est le fruit de l’évolution due à l’augmentation de la complexité des projets Java.
Javac
Java est un langage objet compilé et multi-plateforme (« Write once , run anywhere »)
Les fichiers java (.java) sont compilés en bytecode (.class) et interprétés par la JVM (Java Virtual Machine) pour être exécutés sur le système d’exploitation cible (Windows, Unix, Mac …) ;
Le JDK (Java Development Kit) fournit un outil (javac) permettant de compiler les fichiers Java en bytecode.
Limites de javac
Au même titre que d’autres langages (Ada, C++, PL/SQL) Java préconise d’organiser le code en packages. Concrètement ces packages correspondent à des répertoires. Ainsi pour compiler un projet java, il faut appliquer la commande javac à l’ensemble des répertoires. Le travail est fastidieux et source d’erreurs.
Rapidement le besoin d’automatisation de cette tâche s’est fait sentir dans la communauté Java.
ANT : début de l'automatisation
Présentation
Site officiel : http://ant.apache.org/
ANT peut s’apparenter à l’outil make du C permettant de compiler. Pour être indépendant de la plateforme, il est écrit en java.
Fonctionnement
Ant s’appuie sur un fichier de configuration (build.xml) pour exécuter des tâches java (cp, mkdir, javac, jar …) écrites en java au sein de cibles (target) que l’on exécute.
Par exemple
Si on veut faire une librairie java (jar) d’un ensemble de classes, nous allons procéder de la manière suivante :
- Compiler tout les fichiers java avec la tâche javac au sein d’une cible « compile »
- Créer la librairie avec la tâche jar au sein d’une cible « dist » qui dépend de « compile »
<target name="compile" depends="init"
description="compile the source " >
<!-- Compile the java code from ${src} into ${build} -->
<javac srcdir="${src}" destdir="${build}"/>
</target>
<target name="dist" depends="compile"
description="generate the distribution" >
<!-- Create the distribution directory -->
<mkdir dir="${dist}/lib"/>
<!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
<jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
</target>
Apport et limites de ANT
ANT a permis d’automatiser un ensemble de tâches dans les projets java. Cependant cet outil n’imposant aucune structure sa mise en place s’apparente à du procédural Xml. Enfin il ne gère pas la problématique des dépendances entre librairies dans l’écosystème Java.
Les jars sauvages
Présentation
L’écosystème Java étant indépendant de la plateforme (à la différence du C), il permet de créer des librairies (jar) réutilisables. Ainsi très rapidement, la communauté Java a fourni des frameworks (cadre de travail) ou librairies (jar) répondant à des problématiques communes.
Par exemple :
- Gestion des logs : Log4J
- Gestion des tests unitaires : JUnit
- Pattern MVC (Model View Controller) : Struts
- …
Problématique
Ces librairies ou frameworks se concentrent uniquement sur leur cœur de métier, c’est l’une de leurs caractéristiques. Par exemple Struts (MVC) ne gère pas les logs qu’il délègue à Log4J. Utiliser une librairie java utilisant d’autres librairies (avec les bonnes versions) devient alors un vrai casse tête.
Conclusion
Faire un outil qui gère les dépendances et effectue des taches fastidieuses pour les projets Java.
Maven est arrivé
Intérêt
Maven répond à deux problématiques :
- Gestion des dépendances
- Construction des projets Java (uniquement), Maven ne gère pas les projets scala, groovy (langages qui se greffent sur la JVM)
Caractéristiques
- Maven reprend à ANT le formalisme XML pour effectuer les traitements (zéro code Java), mais il va plus loin.
- Maven propose la notion de dépôt (repository) centralisant les librairies du monde java.
- Maven impose une structure et un formalisme, il est déclaratif et non procédural XML comme peut l’être ANT.
Conclusion
À la question « est-ce une mode, un besoin, une geekerie ? ». Maven répond à un besoin et il est devenu le standard de construction (build) des projets Java/JEE.
Pour information d’autres outils font à peu près la même chose que Maven (gradle, ivy …).
Fonctionnement
Pré – requis
Avoir maven installé sur le poste. Pour vérifier que maven est installé et bien configuré : taper dans une fenêtre dos mvn –version
Caractéristiques
Convention over configuration
Maven est basé sur le principe « convention over configuration », il faut suivre les conventions Maven pour travailler avec cet outil. Ainsi Maven sait où aller chercher les éléments (sources java, fichiers de propriétés par exemple, …) et où mettre les éléments générés (class, jar, war …).
Ceci a un impact sur la structure des projets Java :
La différence la plus notable
Dans un projet traditionnel les librairies sont stockées dans le répertoire « lib » là où Maven fait des références vers les dépendances « Maven Dependencies ». Pour le reste, ce ne sont que des conventions.
Les conventions Maven sont simples :
Répertoire |
Description |
src/main/java |
Les sources java |
src/main/ressources |
Les fichiers de ressources (properties, xml …) |
src/test/java |
Les tests unitaires |
src/test/ressources |
Les ressources nécessaires aux tests |
/target |
les fichiers générés pour les artéfacts et les tests. |
/target/classes |
les classes compilées |
/target/test-classes |
les classes compilées des tests unitaires |
Gestion des dépendances
Les dépendances nécessaires au projet sont dans des repositories (dépôts) maven (accessibles depuis Internet). Pour construire un projet Java, Maven télécharge ces librairies depuis internet dans le repository local.
Le repository local est défini dans le fichier M2_HOME\conf\settings.xml dans la balise <localRepository>
Remarque
Si la balise n’est pas renseignée, le repository local est dans le répertoire .m2 de l’utilisateur.
Exemple d’un repository local
Processus de build
POM (Project Object Model)
Le POM (Project Object Model) permet de décrire le logiciel java, c’est un fichier XML suivant la convention Maven à la racine d’un projet Java.
Dans le chapitre suivant nous détaillerons les éléments composant ce fichier.
POM
Les éléments du pom
Les éléments composant le pom.xml sont :
- L’identification du projet
Un pom est définie par :
- Un groupId
- Un artifactId
- Un numéro de version
- Un packaging (pom, jar, war, ear)
- Un nom (important dans le cas de module)
- Une description
<modelVersion>4.0.0</modelVersion> <groupId>com.mastertheboss</groupId> <artifactId>EclipseJPAExample</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>le_nom</name> <description>la_description_si_pas_explicite</description> |
- Properties
Les properties sont englobées dans une balise <properties>, le nom est libre et la place dans le fichier pom également.
On a pour habitude
- de placer les properties juste après l’identification du projet,
- de nommer la propriété de la manière suivante : « nom de dépendance » . « element de la dépendance ». Cette propriété est ensuite utilisée dans le fichier par le formalisme ${nomPropriete}
<properties> <spring-core.version>4.1.6.RELEASE</spring-core.version> </properties>
… Ensuite dans le pom
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-core.version}</version> </dependency>
|
- Dépendances
Les dépendances sont englobées dans une balise <dependencies>
Une dépendance est définie par :
- Un groupId
- Un artifactId
- Un numéro de version
- Un scope (si non précisé la dépendance est incluse dans l’application déployée).
<dependencies> <!-- SPRING --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-core.version}</version> </dependency> … </dependencies> |
Scopes
Le déploiement d’une application ne nécessite pas d’inclure toutes les dépendances. En effet certaines dépendances existent dans le container (Moteur de servlet, serveur d’application JEE) par exemple l’API servlet. D’autres comme les tests n’ont pas été déployées dans le logiciel (JUnit …). Maven définit la portée (scope) des dépendances, permettant de les inclure ou de les exclure dans le logiciel final.
Les différents scopes sont :
Scope |
Description |
compile |
Une dépendance de portée compile est disponible dans toutes les phases. C'est la valeur par défaut. |
provided |
Une dépendance de portée provided est utilisée pour compiler l'application, mais ne sera pas déployée. Vous utiliserez cette portée quand vous attendez du JDK ou du serveur d'application qu'il vous mette le JAR à disposition. L'API servlet est un bon exemple. |
runtime |
Les dépendances de portée runtime ne sont pas nécessaires pour la compilation, uniquement pour l'exécution, comme les drivers JDBC (Java Database Connectivity). |
test |
Les dépendances de portée test sont uniquement nécessaires pour compiler et exécuter les tests (par exemple Junit). |
- La construction
La construction se fait par la balise <build> contenant la balise <plugins>.
Un plugin permet d’effectuer un traitement (compilation, génération d’un war …). La liste des plugins disponible est consultable à l’adresse https://maven.apache.org/plugins/
Un plugin est défini par :
- Un groupId
- Un artifactId
- Un numéro de version
- Une configuration ou non (dépendant du plugin)
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> <compilerArguments> <endorseddirs>${endorsed.dir}</endorseddirs> </compilerArguments> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> ... </plugins> </build> |
phase
L’exécution d’un plugin peut se faire dans une phase de construction du build. Dans ce cas il faut ajouter l’élément « execution » et préciser la phase concernée au plugin.
<build> <plugins> <plugin> <artifactId>maven-myquery-plugin</artifactId> <version>1.0</version> <executions> <execution> <id>execution1</id> <phase>test</phase> <configuration> <url>http://www.foo.com/query</url> <timeout>10</timeout> <options> <option>one</option> <option>two</option> <option>three</option> </options> </configuration> <goals> <goal>query</goal> </goals> </execution> </executions> </plugin> </plugins> </build> |
} Les repositories
Un repository correspond à un dépôt distant permettant de récupérer des dépendances ou des plugins.
Un repository est composé de
- Un identifiant
- Une URL
- Un Nom
<repositories> <repository> <id>EclipseLink Repo</id> <url>http://download.eclipse.org/rt/eclipselink/maven.repo</url> <name>EclipseLink Repo</name> </repository> </repositories> |
Héritage et composition
- Héritage
Un pom peut hériter d’un autre pom, le pom racine s’appelle le pom parent
<parent> <groupId>groupIdPomParent</groupId> <artifactId>artifactIdPomParent</artifactId> <version>versionPomParent</version> </parent> |
- Composition
Un pom peut être composé de plusieurs pom, ceux-ci s’appellent des modules. Dans ce cas un pom parent fait référence à un ou plusieurs sous modules.
<modules> <module>module_presentation</module> <module>module_service</module> <module>module_donnees</module> </modules> |
Dans ce cas chaque module correspond à un projet Maven possédant son propre pom.
} Exemple de mise en œuvre
Dans une application JEE découpée en 3 tiers
Ceci peut être mis en place dans maven par
- un pom parent (l’application)
- trois pom enfant de la manière suivante
- Le cycle de vie de la compilation maven
// TODO
Foireux mieux expliquer
Commande |
Description |
clean |
Nettoyage du projet |
validate |
Valider les informations nécessaires à la génération du projet |
initialize |
Initialiser la génération du projet |
generate-sources |
Générer les sources qui doivent être incluses dans la compilation |
process-sources |
Traiter des sources (par exemple, application d'un filtre) |
generate-resources |
Générer les ressources qui doivent être incluses dans l'artéfact |
process-resources |
Copier les ressources dans le répertoire target |
compile |
Compiler le code source du projet |
process-classes |
Traiter les fichiers class résultant de la compilation (par exemple, pour faire du bytecode enhancement) |
generate-test-sources |
Générer des sources qui doivent être incluses dans les tests |
process-test-sources |
Traiter les sources pour les tests (par exemple, application d'un filtre) |
generate-test-resources |
Générer des ressources qui doivent être incluses dans les tests |
process-test-resources |
Copier les ressources dans le répertoire test |
test-compile |
Compiler le code source des tests |
process-test-classes |
Effectuer des actions sur les classes compilées (par exemple, pour faire du bytecode enhancement) |
test |
Compiler et exécuter les tests unitaires automatisés. |
Prepare-package (à partir de Maven 2.1) |
Effectuer des actions pour préparer la génération du package |
package |
Générer l'artéfact sous sa forme diffusable (jar, war, ear, ...) |
pre-integration-test |
Effectuer des actions avant l'exécution des tests d'intégration (par exemple configurer l'environnement d'exécution) |
integration-test |
Exécution des tests orientés intégration |
(à partir de Maven 3) |
Compiler et exécuter les tests d'intégration automatisés dans un environnement dédié au besoin en effectuant un déploiement |
post-integration-test |
Effectuer des actions après l'exécution des tests d'intégration (par exemple faire du nettoyage dans l'environnement) |
verify |
Exécuter des contrôles de validation et de qualité |
install |
Installer l'artéfact dans le dépôt local pour qu'il puisse être utilisé comme dépendance d'autres projets |
Deploy |
Déployer l'artéfact dans un environnement dédié et copie de l'artéfact dans le référentiel distant |
Site |
Création du site de documentation projet |
Les commandes les plus utilisées pour la génération du projet sont en gras.
Les patrons de projet : archetype
2.4.1 Présentation
Maven propose de générer des projets grâce à des modèles de projet (archetype)
2.4.2 Liste des modèles disponibles
Pour connaitre la liste des modèles disponible taper dans une fenêtre dos la commande : mvn archetype:generate > liste_archetypes.txt (la liste des modèles est écrite dans le fichier liste_archetypes.txt )
2.4.3 Créer un projet maven à partir d’un archetype
Pour créer un projet maven à partir d’un archetype, taper dans une fenêtre dos la commande :
[cle128822] mvn archetype:generate
Suite à cela choisir le numéro de l’archetype à générer et taper entrée.
Pour que le projet maven soit importable dans eclipse, taper la ligne de commande mvn eclipse :eclipse dans le répertoire du projet créé
Il suffit ensuite d’importer ce projet Maven dans eclipse.
2.5 Création et structure d’un projet Maven
2.5.1 Création d’un projet maven
Dans une fenêtre dos taper la commande maven suivante
mvn archetype:generate -DgroupId=com.open.formation_maven -DartifactId=quickstart -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
Exemple
Importer le projet maven dans eclipse (import / import / maven / Existing Maven project)
Cliquer sur « Next » et sélectionner le répertoire de l’application (dans notre cas « quickstart » correspondant au artifactId de la commande maven)
Cliquer sur « finish »
Le projet maven apparait dans la liste des projets d’eclipse.
2.5.2 Structure d’un projet maven
2.5.3 Présentation
La structure standard d’un projet maven est la suivante :
Explication
- Description du projet : pom.xml est à la racine du projet
- Les sources du projet : le répertoire src
- Les éléments générés (classes, jar, war …) : répertoire target
- Description détaillée de src
3 Normalisation des projets 3 A
3.1 Présentation
Les projets 3A se basent sur une structure Maven spécifique à la Société Générale et détaillée dans le document « Présentation_du_Projet_type_3A.docx » (https://itim.safe.socgen/fr/3a section « Guide de Mise en Œuvre des capacités 3A »
L’utilitaire wizard.bat créé les projets avec la structure suivante :
3.2 Modélisation
3.2.1 Remarque
Ce diagramme modélise les interactions entre les pom des différents projets (xxx, xxx-core, xxx-ear, xxx-ejb, xxx-service, …).
3.2.2 Explications générales
Xxx correspond au pom parent, il hérite lui-même du pom 3a-conventions de la SG, il importe le projet socle-xxx qui gère les dépendances.
Les autres projets xxx-core, xxx-ear, xxx-ejb, xxx-service, xxx-web, xxx-ws héritent du pom parent xxx.
3.2.3 socle-xxx
Le projet socle-xxx est un projet maven « pom » qui centralise les versions des dépendances. C’est dans le fichier pom.xml de ce projet que nous allons renseigner l’ensemble des dépendances utilisées par les autres projets (xxx-core, xxx-ear, xxx-ejb, …).
3.3 Mise en pratique Maven
Nous utiliserons dans la mise en pratique avec Maven le trigramme pia au lieu de xxx
3.3.1 socle-pia
3.3.1.1 Correspondance
Le pom correspond au pom.xml du répertoire socle-pia
3.3.1.2 Objectif
Garder le code généré par le wizzard SG et ajouter toute les dépendances nécessaires aux autres projets Maven. Dans un soucis de maintenabilité, les versions des dépendances seront définies en tant que propriétés : on peut ainsi y accéder par une variable (ex : ${pia-pan-core.version}). Ce procédé simple permet de n’avoir le numéro de version qu’à un seul endroit dans le code, tous modules confondus.
3.3.1.3 Exemple
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<parent> <groupId>com.socgen.conventions</groupId> <artifactId>3a-conventions</artifactId> <version>1.0.5</version> </parent>
<properties>
<!-- version des modules -->
<pia-pan-core.version>1.0.0-SNAPSHOT</pia-pan-core.version> <pia-pan-service.version>1.0.0-SNAPSHOT</pia-pan-service.version> <pia-pan-web.version>1.0.0-SNAPSHOT</pia-pan-web.version> <pia-pan-ws.version>1.0.0-SNAPSHOT</pia-pan-ws.version> <pia-pan-ear.version>1.0.0-SNAPSHOT</pia-pan-ear.version>
<!-- version dépendances applicatives -->
<cdi-api.version>1.0-SP1</cdi-api.version>
<!-- Chemin du Compilateur JDK -->
<jdk.home>${env.MVN_JDK_HOME}\${type.jdk}</jdk.home>
<!-- Build Encoding --> <build.encoding>UTF-8</build.encoding>
</properties>
<groupId>com.socgen.pia-pan</groupId> <artifactId>socle-pia-pan</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <name>Socle_rootArtifactId</name>
<dependencyManagement> <dependencies>
<!-- dépendances des modules -->
<dependency> <groupId>com.socgen.pia-pan</groupId> <artifactId>pia-pan-core</artifactId> <version>${pia-pan-core.version}</version> </dependency> <dependency> <groupId>com.socgen.pia-pan</groupId> <artifactId>pia-pan-service</artifactId> <version>${pia-pan-service.version}</version> </dependency> <dependency> <groupId>com.socgen.pia-pan</groupId> <artifactId>pia-pan-web</artifactId> <version>${pia-pan-web.version}</version> <type>war</type> </dependency> <dependency> <groupId>com.socgen.pia-pan</groupId> <artifactId>pia-pan-ws</artifactId> <version>${pia-pan-ws.version}</version> <type>war</type> </dependency> <dependency> <groupId>com.socgen.pia-pan</groupId> <artifactId>pia-pan-ear</artifactId> <version>${pia-pan-ear.version}</version> <!-- <type>ear</type> --> </dependency>
<!-- dépendances applicatives -->
<!-- CDI -->
<dependency> <groupId>javax.enterprise</groupId> <artifactId>cdi-api</artifactId> <version>${cdi-api.version}</version> </dependency>
</dependencies> </dependencyManagement>
</project>
|
[cle128821] A voir si tu voulais ajouter l’option update : « -U » pour les problèmes de dépendances qu’il peut y avoir des fois
[cle128822]A verifier s’il sagit de la bonne commande