Skip to content

Полезные плагины для maven

wizardjedi edited this page Apr 10, 2013 · 21 revisions

Сборка JAR

Для сборки Jar-файла необходимо использовать соответствующий плагин.

pom.xml

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-jar-plugin</artifactId>
	<configuration>
		<archive>
			<addMavenDescriptor>false</addMavenDescriptor>
			<compress>true</compress>
			<manifest>
				<addClasspath>true</addClasspath>
				<classpathPrefix>libs/</classpathPrefix>
				<mainClass>a1s.client.App</mainClass>
			</manifest>
		</archive>
	</configuration>
	<version>2.4</version>
</plugin>

В данном случае загружается плагин для сборки в jar-файл и производятся настройки:

  • <addMavenDescriptor>false</addMavenDescriptor> - отключает копирование pom.xml и pom.properties в META-INF/maven
  • <compress>true</compress> - использовать сжатие
  • <addClasspath>true</addClasspath> - добавить зависимости в classpath манифеста
  • <classpathPrefix>libs/</classpathPrefix> - путь к библиотекам зависимостей, которые добавляются в classpath
  • <mainClass>a1s.client.App</mainClass> - полное имя класса, в котором используется метод main

Копирование зависимостей

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-dependency-plugin</artifactId>
	<executions>
		<execution>
			<id>copy-dependencies</id>
			<phase>package</phase>
			<goals>
				<goal>copy-dependencies</goal>
			</goals>
			<configuration>
					<outputDirectory>${project.build.directory}/libs</outputDirectory>
			</configuration>
		</execution>
	</executions>
	<version>2.5.1</version>
</plugin>

Данный плагин копирует файлы зависимостей в соответствующую директорию при сборке. Данный плагин реализует цель copy-dependencies, которая включается на этапе package. В качестве конфигурации передаётся директория для копирования файлов зависимостей (${project.build.directory}/libs), в нашем случае это будет target/libs.

Embedded Jetty

<plugin>
	<groupId>org.mortbay.jetty</groupId>
	<artifactId>jetty-maven-plugin</artifactId>
	<version>8.1.8.v20121106</version>
	<configuration>
		<scanIntervalSeconds>10</scanIntervalSeconds>
		<stopKey>foo</stopKey>
		<stopPort>9999</stopPort>
		<connectors>
			<connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">
				<port>9090</port>
				<maxIdleTime>60000</maxIdleTime>
			</connector>
		</connectors>
	</configuration>
</plugin>

Рассмотрим настраиваемые свойства:

  • scanIntervalSeconds - интервал в секундах через который Jetty проверяет директории на изменения для редеплоя приложения
  • connectors - список подключений
  • port - настраивает порт, на котором будет запущен jetty

После подключения плагина стало возможным проводить развёртывание проекта с использованием команды mvn jetty:run.

Работа с системами контроля версий

Проставление версии build'а для проекта

Номер build'а может быть важным инструментов для отслеживания регрессионных багов или поиске неисправленостей при долгосрочной поддержке системы. Поэтому хотелось бы иметь увеличивающийся автоматический счётчик build'ов.

В maven подобной функциональности можно достичь с помощью buildnumber-maven-plugin из org.codehaus.mojo.

Данный плагин позволяет реализовывать версионность билдов на основе:

  • инкрементального счётчика
  • даты (timestamp)
  • версии из системы контроля версий

Данный плагин требует наличия секции с описанием параметров системы контроля версий, даже если используется инкрементальный счётчик или версия на основе времени, поэтому объявим fake'овый раздел <scm />.

pom.xml

<scm>
	<connection>scm:svn:http://127.0.0.1/svn/my-project</connection>
	<developerConnection>scm:svn:https://127.0.0.1/svn/my-project</developerConnection>
	<tag>HEAD</tag>
	<url>http://127.0.0.1/websvn/my-project</url>
</scm>

Теперь подкючим плагин для проставления номера build'а.

pom.xml

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>buildnumber-maven-plugin</artifactId>
	<version>1.1</version>
	<executions>
		<execution>
			<phase>validate</phase>
			<goals>
				<goal>create</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<revisionOnScmFailure>1</revisionOnScmFailure>
		<doCheck>true</doCheck>
		<buildNumberPropertyName>buildNumber</buildNumberPropertyName>
		<doUpdate>true</doUpdate>
		<format>{0,number}</format>
		<items>
			<item>buildNumber</item>
		</items>
	</configuration>
</plugin>

Рассмотрим параметры более подробно:

  • <revisionOnScmFailure>1</revisionOnScmFailure> - номер присваиваемой ревизии в случае, если доступ в систему контроля версий закончился ошибкой
  • <buildNumberPropertyName>buildNumber</buildNumberPropertyName> - наименование свойства, в котором будет сохранён номер build'а
  • <format>{0,number}</format> - формат номера build'а в текущем случае просто цифровое значение
  • <items /> - генерируемые значения
    • <item>buildNumber</item> - название счётчика

соберём проект:

$ mvn clean install
...
[INFO] --- buildnumber-maven-plugin:1.1:create (default) @ testbuildnumber ---
[INFO] Storing buildNumber: 1 at timestamp: 1355932828379
...
$ ls
buildNumber.properties  pom.xml  src  target
$ cat buildNumber.properties
#maven.buildNumber.plugin properties file
#Wed Dec 19 19:00:28 MSK 2012
buildNumber=1

в корне проекта был создан файл buildNumber.properties, в котором и будет сохраняться версия build'а.

Добавление версии в manifest jar файла

Если рассмотреть манифест jar-файла из предыдущего примера, то в нём не окажется версии сборки.

$ unzip -p target/testbuildnumber-1.0.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Built-By: wiz
Build-Jdk: 1.7.0
Created-By: Apache Maven 3.0.4
Main-Class: a1s.client.App
Archiver-Version: Plexus Archiver

Для добавления версии сборки в manifest необходимо добавить соответствующие настройки в плагин сборки jar-файла.

pom.xml (раздел configuration/archive плагина maven-jar-plugin)

<manifestEntries>
	<Implementation-Build>${buildNumber}</Implementation-Build>
</manifestEntries>

полный текст подключения jar-плагина будет таким:

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-jar-plugin</artifactId>
	<configuration>
		<archive>
			<addMavenDescriptor>false</addMavenDescriptor>
			<compress>true</compress>
			<manifest>
				<addClasspath>true</addClasspath>
				<classpathPrefix>libs/</classpathPrefix>
				<mainClass>a1s.client.App</mainClass>
			</manifest>
			<manifestEntries>
				<Implementation-Build>${buildNumber}</Implementation-Build>
			</manifestEntries>
		</archive>
	</configuration>
	<version>2.4</version>
</plugin>

Соберём проект и просмотрим файл манифеста.

$ mvn clean install
...
$ unzip -p target/testbuildnumber-1.0.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Built-By: wiz
Build-Jdk: 1.7.0
Created-By: Apache Maven 3.0.4
Implementation-Build: 2
Main-Class: a1s.client.App
Archiver-Version: Plexus Archiver

Добавление версии и номера build'а в имя jar-файла

Иногда может понадобиться добавлять номер build'а к имени файла. Реализуем нумерацию в виде 1.0.12345, где 1.0 - версия, а 12345 - номер build'а.

Для этого внесём изменение в формат номера build'а:

<format>${project.version}.{0,number}</format>

добавим элемент <finalName /> в раздел <build />.

<finalName>${project.name}-${buildNumber}</finalName>

Соберём проект и посмотрим, что получилось:

$ mvn clean intall
$ ls target/
classes  libs  surefire  surefire-reports  testbuildnumber-1.0.4.jar  test-classes
$ unzip -p target/testbuildnumber-1.0.4.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Built-By: wiz
Build-Jdk: 1.7.0
Created-By: Apache Maven 3.0.4
Implementation-Build: 1.0.4
Main-Class: a1s.client.App
Archiver-Version: Plexus Archiver

Как видно из вывода был собран jar-файл testbuildnumber-1.0.4.jar с указанием номера версии и build'а в имени файла и в файле манифеста внутри jar-архива.

Генерация номера build'а с привязкой ко времени

Добавим в качестве номера build'а текущую дату (в формате yyyy_MM_dd_HH_mm_ss ), для этого добавим следующую настройку:

<format>${project.version}.{0,date,yyyy_MM_dd_HH_mm_ss}</format>

Соберём проект:

$ mvn clean install
$ ls target/
classes  libs  surefire  surefire-reports  testbuildnumber-1.0.2012_12_19_19_48_51.jar  test-classes

Генерация сложного номера build'а

Возможно объединять текущий timestamp и инкрементальный buildnumber.

<format>${project.version}.{0,number}.{1,date,yyyyMMddHHmmss}</format>
<items>
	<item>buildNumber0</item>
	<item>timestamp</item>
</items>
$ mvn clean install
$ ls target/
classes  libs  surefire  surefire-reports  testbuildnumber-1.0.1.20121219201648.jar  test-classes

Форматирование номера build'а

Maven buildnumber plugin использует MessageFormat для обработки свойств, поэтому возможно форматировать свойства в соответствии с правилами.

Например,

  • генерация текущей даты номера build'а <format>{0,date,yyyyMMdd}</format>
  • генерация текущей даты номера build'а <format>{0,date,yyyyMMddHHiiss}</format>

Генерация различных номеров build'а для названия и свойства в JAR-файле

Допустим необходимо сгенерировать 2 разных номера для названия JAR-файла и для свойства в манифесте.

Для этого необходимо разделить генерацию buildnumber'ов по разделам execution разделим buildnumber для имени файла и builddate для свойства в манифесте.

Изменим параметр задания свойства в манифесте:

<manifestEntries>
	<Implementation-Build>${buildNumber} at ${buildDate}</Implementation-Build>
</manifestEntries>

и добавим генерацию 2-х buildnumber'ов:

<executions>
	<execution>
		<id>buildNumber</id>
		<phase>validate</phase>
		<goals>
			<goal>create</goal>
		</goals>
		<configuration>
			<buildNumberPropertyName>buildNumber</buildNumberPropertyName>
			<format>${project.version}.{0,number}</format>
			<items>
				<item>buildNumber0</item>
			</items>
		</configuration>
	</execution>
	<execution>
		<id>buildDate</id>
		<phase>validate</phase>
		<goals>
			<goal>create</goal>
		</goals>
		<configuration>
			<buildNumberPropertyName>buildDate</buildNumberPropertyName>
			<format>{0,date,yyyy-MM-dd HH:mm:ss}</format>
			<items>
				<item>timestamp</item>
			</items>
		</configuration>
	</execution>
</executions>

соберём проект

$ mvn clean install
$ ls target/
classes  libs  surefire  surefire-reports  testbuildnumber-1.0.4.jar  test-classes
$ unzip -p target/testbuildnumber-1.0.4.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Built-By: wiz
Build-Jdk: 1.7.0
Created-By: Apache Maven 3.0.4
Implementation-Build: 1.0.4 at 2012-12-19 20:24:25
Main-Class: a1s.client.App
Archiver-Version: Plexus Archiver

в имя файла добавлен номер build'а, а в манифест полная строка с датой билда.

Создание сборки приложения

Кроме создания JAR-файла с зависимостями может понадобится создать архив со сборков приложения. Для этого понадобится maven-assembly plugin, который может создавать директорию со всеми ресурсами или архивы со сборкой приложения.

Создадим следующуй структуру директорий:

$ tree
.
├── bin
│   └── start.sh
├── dist
│   ├── app-0.0.1-SNAPSHOT.jar
│   └── libs
├── etc
│   └── app.properties
└── jni

Пройдёмся по директориям:

  • bin основная директория, в которой будут скрипты для запуска приложения
  • dist - директория для jar-файлов
    • libs - директория с зависимостями
  • etc - директория с настройками

Добавим в pom.xml использование maven-assembly-plugin. Добавим плагин последним в список плагинов.

pom.xml

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-assembly-plugin</artifactId>
	<version>2.3</version>
	<executions>
		<execution>
			<phase>package</phase>
			<goals>
				<goal>single</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<descriptor>src/main/assembly/bin.xml</descriptor>
	</configuration>
</plugin>

Само же описание сборки располагается в дескрипторе сборки по адресу src/main/assembly/bin.xml.

Рассмотрим дескриптор сборки: bin.xml

<?xml version="1.0" encoding="UTF-8"?>
<assembly
	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2
  http://maven.apache.org/xsd/assembly-1.1.2.xsd">

	<id>bin</id>
	<formats>
		<format>zip</format>
		<format>dir</format>
	</formats>
	<fileSets>
		<fileSet>
			<directory>target/libs</directory>
			<outputDirectory>dist/libs</outputDirectory>
			<includes>
				<include>*.jar</include>
			</includes>
		</fileSet>

		<fileSet>
			<directory>target</directory>
			<outputDirectory>dist</outputDirectory>
			<includes>
				<include>*.jar</include>
			</includes>
		</fileSet>

		<fileSet>
			<directory>src/main/resources/bin</directory>
			<outputDirectory>bin</outputDirectory>
			<includes>
				<include>*.sh</include>
			</includes>
			<fileMode>0755</fileMode>
			<filtered>true</filtered>
		</fileSet>

		<fileSet>
			<directory>src/main/resources/etc</directory>
			<outputDirectory>etc</outputDirectory>
			<includes>
				<include>*</include>
			</includes>
			<filtered>true</filtered>
		</fileSet>

		<fileSet>
			<directory>src/main/resources/jni</directory>
			<outputDirectory>jni</outputDirectory>
			<includes>
				<include>*.so</include>
			</includes>
		</fileSet>
	</fileSets>
</assembly>

Рассмотрим параметры подробнее:

  • <id>bin</id> - идетификатор сборки
  • <formats> - описывает генерируемые форматы сборок (в нашем случае будет просто директория со сборкой и ZIP-файл). Можно указывать несколько форматов для сборки.
  • <fileSets> - описывает наборы файлов для сборки

Рассмотрим параметры fileset'ов на примере диреутории со скрптами запуска:

  • <directory>src/main/resources/bin</directory> - директория откуда копируем
  • <outputDirectory>bin</outputDirectory> - директория куда копируем
  • <includes><include>*.sh</include></includes> - какие файлы копируем?
  • <fileMode>0755</fileMode> - устанавливаем атрибуты файла
  • <filtered>true</filtered> - использовать фильтрацию

Рассмотрим скрипт для запуска приложения: start.sh

#!/bin/bash

cd ..

export LD_LIBRARY_PATH="./jni/"

java -jar ./dist/${project.build.finalName}.jar

В качестве имени jar-файла для запуска используется параметр ${project.build.finalName}, который будет заменён на реальное имя jar-файла.

Соберём проект

$ mvn clean install

После сборки в директории target появится директория по имени файла, в которой собрано приложение и zip-архив с приложением.

Сборка проекта с разделяемыми ресурсами

Может возникнуть ситуация, когда необходимо добавить дополнительные ресурсы в зависимости от профиля, тогда нам поможет component descriptors для maven assembly plugin.

Опишем компонент:

<?xml version="1.0" encoding="UTF-8"?>
<component xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/component/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		   xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/component/1.1.2 http://maven.apache.org/xsd/component-1.1.2.xsd">
	<fileSet>
		<directory>src/main/resources/dump</directory>
		<outputDirectory>dump</outputDirectory>
		<includes>
			<include>*.sql</include>
		</includes>
	</fileSet>
	
</component>

Теперь в файле дескриптор асборки можно подключить этот компонент, например, используя идентификатор профиля в названии:

<componentDescriptors>
	<componentDescriptor>specific-${profile.id}.xml</componentDescriptor>
</componentDescriptors>

Проверка версий используемых зависимостей

Для maven есть плагин для проверки версий зависимостей. pom.xml

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>versions-maven-plugin</artifactId>
	<version>2.0</version>
</plugin>
$ mvn versions:display-dependency-updates
...
[INFO] The following dependencies in Dependencies are using the newest version:
[INFO]   javax.servlet:jstl ............................................... 1.2
[INFO]   joda-time:joda-time-jsptags .................................... 1.1.1
[INFO]   junit:junit ..................................................... 4.11
[INFO]   org.apache.tiles:tiles-core .................................... 3.0.1
[INFO]   org.apache.tiles:tiles-jsp ..................................... 3.0.1
[INFO]   org.eclipse.persistence:eclipselink ............................ 2.3.2
[INFO]   org.eclipse.persistence:javax.persistence ...................... 2.0.3
[INFO]   org.eclipse.persistence:org.eclipse.persistence.jpa.modelgen.processor ...
[INFO]                                                                    2.3.2
[INFO]   org.hibernate:hibernate-annotations ...................... 3.5.6-Final
[INFO]   org.springframework:spring-aop ......................... 3.2.2.RELEASE
[INFO]   org.springframework:spring-beans ....................... 3.2.2.RELEASE
[INFO]   org.springframework:spring-context ..................... 3.2.2.RELEASE
[INFO]   org.springframework:spring-core ........................ 3.2.2.RELEASE
[INFO]   org.springframework:spring-jdbc ........................ 3.2.2.RELEASE
[INFO]   org.springframework:spring-orm ......................... 3.2.2.RELEASE
[INFO]   org.springframework:spring-test ........................ 3.2.2.RELEASE
[INFO]   org.springframework:spring-tx .......................... 3.2.2.RELEASE
[INFO]   org.springframework:spring-web ......................... 3.2.2.RELEASE
[INFO]   org.springframework:spring-webmvc ...................... 3.2.2.RELEASE
[INFO]   org.springframework.security:spring-security-config .... 3.1.3.RELEASE
[INFO]   org.springframework.security:spring-security-core ...... 3.1.3.RELEASE
[INFO]   org.springframework.security:spring-security-ldap ...... 3.1.3.RELEASE
[INFO]   org.springframework.security:spring-security-taglibs ... 3.1.3.RELEASE
[INFO]   org.springframework.security:spring-security-web ....... 3.1.3.RELEASE
[INFO]   taglibs:standard ............................................... 1.1.2
[INFO] 
[INFO] The following dependencies in Dependencies have newer versions:
[INFO]   cglib:cglib ............................................. 2.2.2 -> 3.0
[INFO]   ch.qos.logback:logback-access ........................ 1.0.9 -> 1.0.11
[INFO]   ch.qos.logback:logback-classic ....................... 1.0.9 -> 1.0.11
[INFO]   ch.qos.logback:logback-core .......................... 1.0.9 -> 1.0.11
[INFO]   com.google.guava:guava ............................ 14.0-rc3 -> 14.0.1
[INFO]   com.h2database:h2 ................................. 1.3.170 -> 1.3.171
[INFO]   javax.servlet:servlet-api ......................... 2.5 -> 3.0-alpha-1
[INFO]   javax.servlet.jsp:jsp-api ........................... 2.2 -> 2.2.1-b03
[INFO]   joda-time:joda-time ....................................... 2.1 -> 2.2
[INFO]   mysql:mysql-connector-java .......................... 5.1.21 -> 5.1.24
[INFO]   net.sf.ehcache:ehcache ................................ 2.6.5 -> 2.7.0
[INFO]   org.apache.tomcat:tomcat-jdbc ....................... 7.0.37 -> 7.0.39
[INFO]   org.hibernate:hibernate-c3p0 .............. 4.2.0.Final -> 4.3.0.Beta1
[INFO]   org.hibernate:hibernate-core .............. 4.2.0.Final -> 4.3.0.Beta1
[INFO]   org.hibernate:hibernate-ehcache ........... 4.2.0.Final -> 4.3.0.Beta1
[INFO]   org.hibernate:hibernate-entitymanager ..... 4.2.0.Final -> 4.3.0.Beta1
[INFO]   org.hibernate:hibernate-validator ........... 4.3.1.Final -> 5.0.0.CR5
[INFO]   org.slf4j:jcl-over-slf4j .............................. 1.7.2 -> 1.7.5
[INFO]   org.slf4j:jul-to-slf4j ................................ 1.7.2 -> 1.7.5
[INFO]   org.slf4j:slf4j-api ................................... 1.7.2 -> 1.7.5

Из данного вывода можно увидеть какие версии и каких зависимостей поменялись.

Clone this wiki locally