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ées 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 ira télécharger sur les repositories
distants les jar indiqués comme dépendances, s'ils ne se trouvent pas dans le
repository local.
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 nombre de jars est disponible sur les repositories Maven. Pour les
trouver, le plus simple est d'utiliser le "Google" des packets Maven :
http://www.mvnrepository.com/
Les seuls paramètres obligatoires sont le groupId et l'artifactId.
Il est très vivement 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'a é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'exécution mais pas pour la
compilation.
-
test
: Indique que la dépendance est nécessaire pour la compilation et
l'exécution 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 avoir
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écanisme 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 que certains morceaux d'un framework et de s'abstraire des
dépendances des modules qu'on n'utilisera pas.
|
Une commande bien utile permet d'afficher dans la console la résolution des
dépendances de Maven sur le projet. Cela permet souvent de découvrir
pourquoi un artifact que l'on ne veut pas est inclu 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 situations 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
récente. Suivant les versions de Maven et le plugin qui utilise la
résolution 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ésentes dans le répertoire
WEB-INF/lib.
Pour gérer ce cas de figure, il faut utiliser les exclusions qui permettent
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éfinis 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 local 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 prend é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 même 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écanisme 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 serveurs 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épond à 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ées 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.