Utiliser Maven 2
Date de publication : 04/08/2008 , Date de mise à jour : 04/08/2008
6. Gestion des dépendances du projet
6.1. Dépendances du projet
6.2. Gestion précise des dépendances
6.2.1. Dépendances transitives
6.2.2. Exclusions
6.3. Installation du projet
6.4. Ajouter un jar dans un repository
6.5. Proxy d'entreprise
6. Gestion des dépendances du projet
Pour en revenir aux principes de Maven, le répertoire
src
ne doit contenir que des fichiers sources apporté au projet. Dans cette idée, des
librairies externes utilisées par le projet ne doivent être que des liens vers
d'autres artifacts Maven et surtout pas copié dans le répertoire
src
du projet.
Maven propose de le définir par configuration dans le pom.xml. C'est ensuite le
plugin Maven de gestion de dépendances qui se charge de télécharger les jar
indiqués.
6.1. Dépendances du projet
La configuration à ajouter dans le fichier pom.xml est la suivante :
Configuration d'une dépendance |
< dependencies >
...
< dependency >
< groupId > org.springframework< / groupId >
< artifactId > spring-beans< / artifactId >
< version > 2.0.5< / version >
< type > jar< / type >
< scope > compile< / scope >
< / dependency >
...
< / dependencies >
|
Un grand notre de jars est disponible sur les repository Maven. Pour les
trouver, le plus simple est d'utiliser le "Google" des packets Maven :
http://www.mvnrepository.com/
Les seuls paramètres obligatoire sont le groupId et l'artifactId.
Il est extrêmmement recommandé de toujours spécifier la version.
Sans cela, Maven utilise toujours la dernière version en date. Il est tout à
fait possible que la mise à jour d'une dépendance publiée dans une version alpha
soit automatiquement utilisée et empêche le projet de tourner alors qu'aucune
modification n'ait été aportée.
Le type n'est jamais nécessaire sauf dans des cas particuliers.
Le paramètre scope est parfois nécessiare. Les différentes valeurs à prendre en
compte sont les suivantes :
-
compile
: C'est la valeur par défaut, la dependance sera toujours disponible dans le
classpath.
-
provided
: Indique que la dépendance est nécessaire pour la compilation mais sera
fourni par le container ou le JDK et donc ne sera pas fourni dans le
package.
-
runtime
: Indique que la dépendance est nécessaire pour l'execution mais pas pour la
compilation.
-
test
: Indique que la dépendance est nécessaire pour la compilation et
l'execution des tests unitaires.
Le scope provided est très interessant pour les servlet. Les jars sont fournis
automatiquement par Tomcat (ou Jetty...) mais il est nécessaire de les avoirs
pour la compilation.
|
Par exemple, si on veut utiliser log4j dans notre projet, il faut enrichir le
pom.xml avec la dépendance :
|
pom.xml avec la première dépendance |
< 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/maven-v4_0_0.xsd " >
< modelVersion > 4.0.0< / modelVersion >
< groupId > com.developpez< / groupId >
< artifactId > cours-maven-example< / artifactId >
< packaging > jar< / packaging >
< name > Projet d'exemple pour le cours Maven< / name >
< version > 1.0< / version >
< dependencies >
< dependency >
< groupId > log4j< / groupId >
< artifactId > log4j< / artifactId >
< version > 1.2.13< / version >
< / dependency >
< / dependencies >
< build >
< plugins >
< plugin >
< groupId > org.apache.maven.plugins< / groupId >
< artifactId > maven-compiler-plugin< / artifactId >
< version > 2.0.2< / version >
< configuration >
< source > 1.5< / source >
< target > 1.5< / target >
< / configuration >
< / plugin >
< / plugins >
< / build >
< / project >
|
|
On peut alors ajouter dans le code Java l'utilisation de la dépendance.
|
Classe utilisant la dépendance Maven |
package com.developpez;
import org.apache.log4j.Logger;
public class Test {
Logger logger = Logger.getLogger (this .getClass ());
public void main (String[] args) {
logger.debug (" Hello, World " );
}
}
|
|
Enfin, lors de la compilation, la dépendance sera automatiquement résolue :
|
Téléchargement par Maven des dépendances |
~/cours-maven-example$ mvn compile
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building Projet d'exemple pour le cours Maven
[INFO] task-segment: [compile]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
Downloading: http://repo1.maven.org/maven2/log4j/log4j/1.2.13/log4j-1.2.13.pom
389b downloaded
Downloading: http://repo1.maven.org/maven2/log4j/log4j/1.2.13/log4j-1.2.13.jar
349K downloaded
[INFO] [compiler:compile]
[INFO] Compiling 1 source file to ~\cours-maven-example\target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6 seconds
[INFO] Finished at: Tue Aug 12 15:38:23 CEST 2008
[INFO] Final Memory: 3M/8M
[INFO] ------------------------------------------------------------------------
|
6.2. Gestion précise des dépendances
6.2.1. Dépendances transitives
La gestion des dépendances de Maven gère les dépendances transitives. Si un
artifact X dépend d'un artifact Y qui dépend d'un artifact Z. La résolution
des dépendances de X trouvera Y et Z.
Ce méchanisme implique souvent le téléchargement de beaucoup de librairies.
Chaque artifact va dépendre de tous les autres dont il est suceptible
d'avoir besoin.
La réponse à la multiplication des dépendances est la division en modules
des grands frameworks (voir plus loin les projets modulaires). Cela permet
de n'utiliser seulement certains morceaux d'un framework et de s'abstraire
des dépendances des modules qu'on utilisera pas.
|
Une commande bien utile permet d'afficher dans la console la résolution des
dépandances de Maven sur le projet. Cela permet souvent de découvrir
pourquoi un artifact dont on ne veut pas est inclue dans notre projet.
|
|
Sur notre projet, nous pouvons voir le résultat de cette commande :
|
Affichage de l'arbre des dépendances |
~/cours-maven-example$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'dependency'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Projet d'exemple pour le cours Maven
[INFO] task-segment: [dependency:tree]
[INFO] ------------------------------------------------------------------------
[INFO] [dependency:tree]
[INFO] com.developpez:cours-maven-example:jar:1.0
[INFO] \- log4j:log4j:jar:1.2.13:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 12 seconds
[INFO] Finished at: Tue Aug 19 13:40:35 CEST 2008
[INFO] Final Memory: 8M/18M
[INFO] ------------------------------------------------------------------------
|
6.2.2. Exclusions
En allant plus loin, il est possible de trouver des situation ou les
dépendances transitives posent problèmes.
Par exemple, une dépendance transitive sur un framework dans une version
trop vieille peut poser problème si votre application utilise une version
recente. Suivant les versions de Maven et le plugin qui utilise la réolution
de dépendance
il n'est pas possible de savoir précisément quelle version de l'artifact
sera utilisé.
Notamment dans les packaging war, il est possible que les deux fichiers jar
avec les deux versions différentes soit présente dans le répertoire
WEB-INF/lib.
Pour gérer ce cas de figure, il faut utiliser les exclusions qui permette
d'interdire les dépendances transitives. La syntaxe sera la suivante :
Configuration d'une exclusion dans les dépendances |
< dependencies >
...
< dependency >
< groupId > org.hibernate< / groupId >
< artifactId > hibernate< / artifactId >
< version > 3.2.6.ga< / version >
< exclusions >
< exclusion >
< groupId > net.sf.ehcache< / groupId >
< artifactId > ehcache< / artifactId >
< / exclusion >
< / exclusions >
< / dependency >
...
< / dependencies >
|
L'exclusion ne fonctionne qu'a un seul niveau de profondeur.
L'exemple ci dessous fonctionne car EhCache est une dépendance directe
d'Hibernate. Si EhCache était une dépendance d'une dépendance d'Hibernate,
l'exclusion n'aurait aucun effet.
|
Sur notre projet, pour ajouter la dernière version d'hibernate avec la
dernière version d'EhCache, il faudrait ajouter le code suivant :
|
Configuration des dépendances avec le remplacement d'une version de librairie |
< dependencies >
< dependency >
< groupId > log4j< / groupId >
< artifactId > log4j< / artifactId >
< version > 1.2.13< / version >
< / dependency >
< dependency >
< groupId > org.hibernate< / groupId >
< artifactId > hibernate< / artifactId >
< version > 3.2.6.ga< / version >
< exclusions >
< exclusion >
< groupId > net.sf.ehcache< / groupId >
< artifactId > ehcache< / artifactId >
< / exclusion >
< / exclusions >
< / dependency >
< dependency >
< groupId > net.sf.ehcache< / groupId >
< artifactId > ehcache< / artifactId >
< version > 1.5.0< / version >
< / dependency >
< / dependencies >
|
| L'arbre des dépendances ressemble alors à cela : |
Arbre des dépendances |
~/cours-maven-example$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'dependency'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Projet d'exemple pour le cours Maven
[INFO] task-segment: [dependency:tree]
[INFO] ------------------------------------------------------------------------
[INFO] [dependency:tree]
[INFO] com.developpez:cours-maven-example:jar:1.0
[INFO] +- log4j:log4j:jar:1.2.13:compile
[INFO] +- org.hibernate:hibernate:jar:3.2.6.ga:compile
[INFO] | +- javax.transaction:jta:jar:1.0.1B:compile
[INFO] | +- commons-logging:commons-logging:jar:1.0.4:compile
[INFO] | +- asm:asm-attrs:jar:1.5.3:compile
[INFO] | +- dom4j:dom4j:jar:1.6.1:compile
[INFO] | +- antlr:antlr:jar:2.7.6:compile
[INFO] | +- cglib:cglib:jar:2.1_3:compile
[INFO] | +- asm:asm:jar:1.5.3:compile
[INFO] | \- commons-collections:commons-collections:jar:2.1.1:compile
[INFO] \- net.sf.ehcache:ehcache:jar:1.5.0:compile
[INFO] +- backport-util-concurrent:backport-util-concurrent:jar:3.1:compile
[INFO] \- net.sf.jsr107cache:jsr107cache:jar:1.0:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 12 seconds
[INFO] Finished at: Tue Aug 19 13:40:35 CEST 2008
[INFO] Final Memory: 8M/18M
[INFO] ------------------------------------------------------------------------
|
6.3. Installation du projet
Tous les projets sont définits comme des paquets Maven. Il est donc possible de
publier ces paquets.
Tout d'abord pour publier dans le localrepository, il suffit d'utiliser le goal
install :
Pour l'installer sur un repository externe, il faut lui configurer dans le
pom.xml la gestion de la distribution :
Configuration pour le déploiement du projet |
< distributionManagement >
< repository >
< id > ganesh3-repo< / id >
< name > Ganesh Repository for Maven2< / name >
< url > file://${deploy.repository}< / url >
< / repository >
< / distributionManagement >
|
L'URL peut être exprimé sur beaucoup de protocoles, ici on voit file, mais cela
peut être également scp, http (à condition qu'il y ait un webdav) etc...
6.4. Ajouter un jar dans un repository
On finit toujours par utiliser un jar qui n'est sur aucun respository Maven.
Pourtant, les principes de Maven nous interdisent d'ajouter un jar directement
dans les sources du projet.
Pour venir à bout de cette particularité, Maven propose la possibilité d'ajouter
manuellement des artifacts dans les repository. Une fois installé, il est
possible d'en dépendre de la facon habituelle.
Pour installer dans le repository locale un artifact à partir d'un fichier, il
faut utiliser le goal
instal:instal-file
. La commande n'est pas très belle à voir car elle prends énormément de
paramètres. Il ne faut pas en avoir peur, il s'agit simplement de renseigner en
ligne de commande les informations nécessaires à définir l'artifact qui
correspondra au fichier qu'on instale :
Commande pour installer un artifact a partir d'un fichier |
mvn install:install-file -Dfile=your-artifact-1.0.jar \
[-DpomFile=your-pom.xml] \
[-DgroupId=org.some.group] \
[-DartifactId=your-artifact] \
[-Dversion=1.0] \
[-Dpackaging=jar] \
[-Dclassifier=sources] \
[-DgeneratePom=true] \
[-DcreateChecksum=true]
|
Il existe la meme commande pour installer un artifact dans un repository
distant. Il s'agira cette fois ci du goal
deploy:deploy-file
.
Commande pour deployer un artifact a partir d'un fichier |
mvn deploy:deploy-file -Durl=file://C:\m2-repo \
-DrepositoryId=some.id \
-Dfile=your-artifact-1.0.jar \
[-DpomFile=your-pom.xml] \
[-DgroupId=org.some.group] \
[-DartifactId=your-artifact] \
[-Dversion=1.0] \
[-Dpackaging=jar] \
[-Dclassifier=test] \
[-DgeneratePom=true] \
[-DgeneratePom.description="My Project Description"] \
[-DrepositoryLayout=legacy] \
[-DuniqueVersion=false]
|
6.5. Proxy d'entreprise
Si on prend les sources d'un projet Maven, elle ne contiennent pas les
dépendances. Pourtant, dès qu'on lancera une commande de compilation, les
dépendances seront téléchargées sur le poste.
Ce méchanisme est très puissant mais se repose sur une supposition qui peut
avoir ses limites : toutes les librairies sont toujours disponibles sur
Internet. Le corrollaire est que si certains serveur Web sont en panne au moment
où l'ont désire compiler notre projet, la compilation va échouer.
Il est également souvent nécessaire dans une entreprise de posséder un
repository interne qui permet de rendre accessible facilement les librairies de
l'entreprise.
Le principe du proxy d'entreprise réponds à ces attentes. Son fonctionnement est
le suivant : lorsqu'une instance de Maven sur un poste de développeur demande un
artifact, il s'adresse au proxy (via la configuration dans le pom). Le proxy va
allors chercher l'artifact sur Internet et lui rendre. Lors de la seconde
demande, l'artifact sera immédiatement disponible sur le proxy.
Le plus souvent, le proxy d'entreprise propose aussi la fonctionnalité de
repository d'entreprise et propose des solutions simplifié pour déployer des
artifact dessus.
Les solutions les plus courantes pour fournir ce service sont les suivantes :
Les sources présentés sur cette pages sont libre de droits, et vous pouvez les utiliser à
votre convenance. Par contre cette page de présentation de ces sources constitue une oeuvre
intellectuelle protégée par les droits d'auteurs. Copyright Matthieu Lux . Aucune
reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu
: textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous
encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérets.