Maven : Description - Configuration

Rédigé par niconux Aucun commentaire
Classé dans : Développement, Mémo Mots clés : Maven

Maven est un outil de gestion de projet Java en général et Java EE en particulier qui comprends :

  • un modèle objet pour définit un projet
  • un ensemble de standards
  • un cycle de vie
  • un système de gestion de dépendances

Géré par la l'organisation Apache Software Foundation.

Maven s'apparente à l'outils Ant mais fournit des moyens de configurations plus simples, eux aussi basés sur le format XML.

Maven utilise un paradigme connu sous le nom de Project Object Model (POM) afin de décrire un projet logiciel, ses dépendances avec des modules externes et l'ordre à suivre pour sa production. Maven a un approche basé sur des conventions plus que sur de la configurations comme nous allons le voir par la suite.

Maven établit des conventions raisonnables sur la structure du projet :

  • Sources dans src
  • Code livrables dans src/main
  • Les ressources dans src/main/resources
  • Code tests dans src/text
  • Tout ce qui est construit dans target
  • Code généré dans target/generates-sources
  • ...

Cette approche basée sur de la conventions permet d'avoir moins de configuration pour chaque plugin, plus d'homogénéité entre projets.

Un projet basique peut-être compilé, testé, packagé par Maven sans configuration dédié.

Exemple d'un projet basique déclarant une dépendance sur log4j, ceci est un fichier POM :

<?xml version="1.0" encoding="UTF-8"?>
<project>
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.mycompany</groupId>
	<artifactId>foo</artifactId>
	<version>1.0.0</version>
	<dependencies>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.12</version>
		</dependency>
	</dependencies>
	<build></build>
</project>

Cycle de vie

  1. Validate : Valide que le projet est correctement défini.
  2. Compile : Compile les sources.
  3. Test : Lance les test unitaires.
  4. Package : Prépare la distribution du projet (archives Jar, War, Ear, ...).
  5. Integration-test : Lance les tests d'intégration.
  6. Verify : Lance des tests de validation du package crée.
  7. Install : Installe le package en local sur la machine pour pouvoir être réutilisé comme dépendance.
  8. Deploy : Déploie le package sur un serveur pour qu'il puisse être réutilisé par tout le monde.

L'ensemble des commandes (goals) sont passées de façon sequentielle dans cet ordre, certaines peuvent être évitées (par exemple les tests, via le paramètre -DskipTests, ...)

Plugins : Toujours plus

Il est très facile d'ajouter un plugin de différentes natures sans impact sur l'existant :

  • D'outillage de test
  • Contrôle qualité
  • Génération de code
  • Packaging spécifique
  • ...

De très nombreux plugins sont proposés, certains sont officiels d'autres communautaires.

Plugins officiellement supportés : http://maven.apache.org/plugins/

Plugins communautaires : http://mojo.codehaus.org/

Si vous avez des besoins spécifiques l'écriture d'un plugin est facile (plus que celle d'une tâche ANT), il est peut-être écrit en Java, Groovy, BeanShell, ...

Les dépendances

Maven gère les dépendances nécessaire au projet, la transitivité des dépendances, ...

  • Si mon projet dépend d'Hibernate
  • Hibernate dépend d'EHcache
  • Mon projet dépend d'EHcache

Maven encourage les librairies ciblées plutôt que le gros JAR qui fait tout.

Repository

Un repository est un dépôts de librairies, ces dépôts peuvent être de différentes natures :

  • Dépôt local ($HOME/.m2/repository) : évite la multiplication des .jar sur le poste de dev.
  • Dépôt(s) public(s) (http://repo1.maven.org/maven) : Mise à disposition rapide des librairies libres
  • Dépôt privé : Gestion fine des librairies, libres ou non.

Extrapolation

Les valeurs des attributs XML peuvent être déduites d'une propriétés :

<properties>
	<spring.version>2.5.5</spring.version>
</properties>

Profils

Les profils permettent de personnaliser, de spécialiser le build. Sur un projet d'entreprise, le build pourra être profilé pour différents environnements :

  • Profil "dev"
  • Profil "integrationcontinu"
  • profil "release"
  • profil "prod"
  • ...

L'activitation d'un profil se fait via le paramètre -PXXX où XXX est le nom du profil.

Exemple : mvn clean package -Pdev

Archetype

Dès lors que vous avez créé un projet Maven répondant à vos attentes en terme de dépendances, de plugins, de profils, ... vous pouvez utiliser le pom de ce projet "coquille vide" comme base pour vos futurs développement : ce que l'on appelle un archetype.

Une fois dans le dossier de votre projet, saisir la commande suivante :

  • mvn archetype:create-from-project

Le patron de notre template de projet qui sera utilisé par maven lors de l’appel au goal archetype:generate se trouve dans le répertoire src/main/resources/archetype-resources/src

Dans le répertoire src/main/resources/META-INF/maven, se trouve le fichier archetype-metadata.xml qui contient le descriptif de ce qui doit être généré

Il n’y a plus qu’à exécuter la commande mvn install pour déployer l’archetype dans le repository local

Une fois l’archetype déployé dans le repository, il n’y a plus qu’à l’invoquer via la commande :

  • mvn archetype:generate \
    -DarchetypeGroupId=fr.appli \
    -DarchetypeArtifactId=project-template-archetype \
    -DarchetypeVersion=0.0.1-SNAPSHOT \
    -DgroupId=fr.test\
    -DartifactId=test-archetype

Les bonnes pratiques

  • Adapter le projet à Maven, pas l'inverse
  • Utiliser des plugin ciblés et simple
  • Utiliser les dépendances directes
  • Surveiller toutes les dépendances et les doublons
  • Rester indépendant de l'environnement ... éviter les settings.xml exotiques
  • Renseigner la version de Java ciblée
  • Renseigner l'encodage de votre projet au sein du pom.xml pas dans votre EDI préféré.
  • Renseigner les différentes versions des différences libraires que vous utilisez, évitez de renseigner la version de JAVA, Spring, ... en dur.

Exemple d'un pom utilisant Spring, Hibernate (JPA), une base MySQL pour un profil de production, une base HSQL pour l'environnement de développement.

Le pom suivant utilise certains plugins pour automatiser certains traitements comme :

  • Déployer votre projet à l'aide de Maven plutôt qu'à l'aide de votre EDI
  • Générer un numéro de build à chaque déploiement de votre projet
  • Copier votre projet (war, jar, etc) dans un dossier spécifique.
  • Lancer un script (.bat, .sh, ...) lors d'une étape spécifique du cycle de génération de votre projet (par exemple sur l'étape install). Le script pouvant prendre en argument des paramètres.

Le fichier pom.xml d'explemple étant assez complet, il peut servir de base comme archetype pour le développement de projet similaire.

<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>
	<groupId>fr.appli</groupId>
	<artifactId>projet-web</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>projet-web</name>
	<description>projet spring-ioc, spring-mvc, jpa - projet de base pour un archetype</description>
	<properties>
		<encoding>UTF-8</encoding>
		<!-- declaration des 
			versions des dependances -->
		<version.java>1.7</version.java>
		<version.spring>4.0.1.RELEASE</version.spring>
		<version.jpa>4.3.1.Final</version.jpa>
		<!-- Genere un conflit 
			avec la version de spring 
			attendu 3.1.4 (cf vue 
			dependency), utilisée 
			4.0.1 : le resultat peut 
			etre aleatoire ... faut 
			tester -->
		<version.spring.data>1.4.4.RELEASE</version.spring.data>
		<version.hsqldb>2.3.1</version.hsqldb>
		<version.mysql>5.1.29</version.mysql>
		<version.dbcp>1.4</version.dbcp>
		<version.jstl>1.2</version.jstl>
		<version.war.plugin>2.4</version.war.plugin>
	</properties>
	<!-- If you have access 
		to scm then you can place 
		actual url's. Otherwise 
		with <revisionOnScmFailure 
		/> you can give some 
		fake URLs as follows. -->
	<scm>
		<connection>scm:svn:http://none</connection>
		<developerConnection>scm:svn:https://none</developerConnection>
		<url>scm:svn:https://none</url>
	</scm>
	<dependencies>
		<!-- Spring -->
		<!-- apres test ... 
			pour eviter un conflit 
			avec la version asm demande 
			par spring-data, sans 
			cette dependance, l'asm 
			rappatriee est dans une 
			mauvaise version -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<!-- Spring-ORM -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${version.spring}</version>
		</dependency>
		<!-- Spring-data (generation 
			auto des dao) -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>${version.spring.data}</version>
		</dependency>
		<!-- hibernate -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${version.jpa}</version>
		</dependency>
		<!-- basicdatasource -->
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>${version.dbcp}</version>
		</dependency>
		<!-- JSTL -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>${version.jstl}</version>
		</dependency>
	</dependencies>
	<!-- PROFILS -->
	<profiles>
		<profile>
			<id>dev</id>
			<activation>
				<activeByDefault>
					true
				</activeByDefault>
			</activation>
			<properties>
				<datasource.driverClassName>
					org.hsqldb.jdbcDriver 
				</datasource.driverClassName>
				<database.url>
					jdbc:hsqldb:mem:testdb 
				</database.url>
				<database.username>sa</database.username> <!-- sa -->
				<database.password></database.password> <!-- vide -->
				<jpa.database>HSQL</jpa.database>
				<!-- definit ici 
					ou au debut du pom, au 
					choix -->
				<!-- <version.hsqldb>2.3.1</version.hsqldb> -->
			</properties>
			<dependencies>
				<dependency>
					<groupId>org.hsqldb</groupId>
					<artifactId>hsqldb</artifactId>
					<version>${version.hsqldb}</version>
				</dependency>
			</dependencies>
			<build>
				<plugins>
					<!-- Permet de personnaliser 
						la construction du war 
						(modif manifest, ...) -->
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-war-plugin</artifactId>
						<version>${version.war.plugin}</version>
						<!-- on definit 
							pas de goal etc car il 
							sera appele lors du packaging -->
						<configuration>
							<webResources>
								<resource>
									<!-- relative 
										to the pom.xml directory -->
									<directory>
										src/main/resources/dev 
									</directory>
								</resource>
							</webResources>
							<!-- dossier ou 
								sera déposé le war -->
							<outputDirectory></outputDirectory>
							<!-- chemin vers 
								le dossier webapp du 
								projet (src/main/webapp) -->
							<webappDirectory></webappDirectory>
						</configuration>
					</plugin>
				</plugins>
				<resources>
					<resource>
						<directory>src/main/resources</directory>
						<filtering>true</filtering>
					</resource>
				</resources>
			</build>
		</profile>
		<profile>
			<id>prod</id>
			<properties>
				<database.url>jdbc:mysql//localhost:3306/baseprod 
				</database.url>
				<datasource.driverClassName>org.mysql.jdbc.Driver 
				</datasource.driverClassName>
				<database.username>user</database.username>
				<database.password>14247</database.password>
				<jpa.database>MYSQL</jpa.database>
			</properties>
			<dependencies>
				<dependency>
					<groupId>mysql</groupId>
					<artifactId>mysql-connector-java</artifactId>
					<version>${version.mysql}</version>
				</dependency>
			</dependencies>
			<build>
				<plugins>
					<!-- Permet de personnaliser 
						la construction du war 
						(modif manifest, ...) -->
					<!-- marche pas 
						top ce plugin -->
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-war-plugin</artifactId>
						<version>${version.war.plugin}</version>
						<!-- on definit 
							pas de goal etc car il 
							sera appele lors du packaging -->
						<configuration>
							<packagingExcludes>
							WEB-INF/classes/dev
							</packagingExcludes>
							<webResources>
								<resource>
									<!-- relative 
										to the pom.xml directory -->
									<directory>
									src/main/resources/prod
									</directory>
									<filtering>true</filtering>
									<targetPath>
										WEB-INF/classes 
									</targetPath>
								</resource>
							</webResources>
						</configuration>
					</plugin>
				</plugins>
				<resources>
					<resource>
						<directory>src/main/resources</directory>
						<filtering>true</filtering>
					</resource>
				</resources>
			</build>
		</profile>
	</profiles>
	<build>
		<!-- declare le nom 
			du war cree / nom du 
			projet -->
		<!-- ${project.version} 
			: numero de version du 
			projet (ce qui est declare 
			dans le <version> du 
			project -->
		<finalName>${project.name}.${buildNumber}</finalName>
		<!-- goal lance par 
			defaut : appel mvn -->
		<defaultGoal>clean package</defaultGoal>
		<plugins>
			<!-- Parametrage de 
				la compilation : version 
				des sources/jdk utilise -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version> <!-- voir la version 
					dans le core de maven 
					http://maven.apache.org/plugins/ -->
				<configuration>
					<source>${version.java}</source>
					<target>${version.java}</target>
				</configuration>
			</plugin>
			<plugin>
				<!-- permet de creer 
					un numero de build, qui 
					est dispo dans la variable 
					${buildNumber} -->
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>buildnumber-maven-plugin</artifactId>
				<version>1.2</version>
				<executions>
					<execution>
						<phase>validate</phase>
						<goals>
							<goal>create</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<doCheck>false</doCheck>	<!-- ne se connecte pas 
						au scm -->
					<doUpdate>false</doUpdate>	<!-- ne fait pas d'update -->
					<!-- This ensures 
						that even if we are not 
						connected to scm than 
						also take the version 
						from local .svn file -->
					<revisiononscmfailure>true</revisiononscmfailure>
					<!-- Generate sequence 
						build number based on: 
						build number and timestamp -->
					<!-- <format>Build: 
						#{0} ({1,date})</format> -->
					<!-- ({1,date,yyyy-MM-dd 
						HH:mm:ss}) -->
					<format>{0}
						({1,date,yyyy-MM-dd})</format>
					<items>
						<!-- <item implementation="java.lang.Integer">0</item> -->
						<item>buildNumber\d*</item>
						<item>timestamp</item>
					</items>
				</configuration>
			</plugin>
			<!-- Ajout du plugin 
				permettant de piloter 
				tomcat : goal utilisable 
				par exemple : mvn tomcat7:deploy 
				; mvn tomcat7:undeploy -->
			<plugin>
				<groupId>org.apache.tomcat.maven</groupId>
				<artifactId>tomcat7-maven-plugin</artifactId>
				<version>2.2</version>
				<configuration>
					<!-- id du serveur 
						definit dans le conf/settings.xml 
						de maven ... <server> 
						<id>tomcatdev</id> <username>tomcat</username> 
						<password>tomcat</password> 
						</server> ... -->
					<server>tomcatdev</server>
					<!-- url de deploiement 
						d'applicatif -->
					<url>http://localhost:8080/manager/text</url>
				</configuration>
				<!-- commande dexecution -->
				<executions>
					<execution>
						<id>deploy-tomcat</id>
						<!-- phase dans 
							le cycle de vie de maven -->
						<phase>install</phase>
						<!-- une fois dans 
							install lance le goal 
							: deploy du plugins tomcat.maven -->
						<goals>
							<!-- tache(s) 
								du plugin -->
							<goal>undeploy</goal>
							<!-- deploy le 
								war présent -->
							<goal>deploy-only</goal>	<!-- ou "deploy" mais 
								cela fork le cycle de 
								build, de vie de maven -->
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-antrun-plugin</artifactId>
				<version>1.7</version>
				<executions>
					<execution>
						<id>ant-copy</id>
						<!-- phase dans 
							le cycle de vie de maven -->
						<phase>install</phase>
						<!-- une fois dans 
							install lance le goal 
							: deploy du plugins antrun -->
						<goals>
							<!-- tache(s) 
								du plugin -->
							<goal>run</goal>
						</goals>
						<configuration>
							<target
								name="copy file to partage"
							>
<copy
		file="${project.build.directory}/${project.name}.${buildNumber}.war"
		tofile="c:/temp/${project.name}.${buildNumber}.war" />
							</target>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>exec-maven-plugin</artifactId>
				<version>1.2.1</version>
				<executions>
					<execution>
						<phase>install</phase>
						<goals>
							<goal>exec</goal>
						</goals>
						<configuration>
							<executable>C:\temp\script.bat</executable>
							<arguments>
								<argument>"${env.JAVA_HOME}"</argument>
								<!-- commande 
									maven exploitant l'argument 
									argToto : mvn clean install 
									-DargToto=test -->
								<argument>"${argToto}"</argument>
							</arguments>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

Conclusion

J'espère que ce petit tour d'horizon de Maven vous aura aidé à en comprendre la philosophie, l'usage et sa personnalisation.

Si vous désirez aller plus loin dans l'utilisation de Maven, sa configuration, etc il existe de très bons livres en français ou en anglais : http://maven.apache.org/articles.html

Vous pouvez aussi retrouver énormément de documentation sur le site du projet directement : http://maven.apache.org/guides/index.html

Écrire un commentaire

Quelle est le troisième caractère du mot ia10dg ?

Fil RSS des commentaires de cet article