javabreiz

javabreiz

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. 

evolution-2.jpg

 

Javac

Java est un langage objet compilé et multi-plateforme (« Write once , run anywhere »)

javac.jpg

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 

 

ant.png

 

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

[cle128821] 

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



11/06/2016
0 Poster un commentaire

Inscrivez-vous au blog

Soyez prévenu par email des prochaines mises à jour