IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

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.

info Gestion des dépendances
idea 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>
				
idea 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");
	    }
	}
				
idea 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.

info 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.

	mvn dependency:tree
					
idea 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.

idea 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>
					
ideaL'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 :

	mvn 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]
				
info Utiliser le goal instal:instal-file
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]
				
info Utiliser le goal deploy:deploy-file

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 :

info Les systemes de repository management sur le site de Maven
 

Valid XHTML 1.1!Valid CSS!

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.