В статье о сборочных циклах я писал, что maven предоставляет инфраструктуру и устанавливает правила, а всю настоящую работу делают плагины. Какие же это плагины и какие у них настройки?
Каждый maven плагин имеет собственные maven координаты, такие же как у зависимостей: groupId:artifactId:version. Плагины бывают двух типов — плагины сборки и плагины отчётности. Плагины каждого типа настраиваются в собственной секции pom.xml — соответственно <build/> и <report/>. Типичная конфигурация плагина в maven выглядит следующим образом:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<build>
<plugins>
<plugin>
<groupId>group</groupId>
<artifactId>artifact</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<goals>
<goal>somePluginGoal</goals>
<goals>
<phase>integration-test</phase
</execution>
</executions>
<configiuration>
<some>values</some>
</configuration>
</plugin>
</plugins>
</build>
|
Секция executions связывает цели плагинов с фазами циклов сборки, а секция configuration позволяет задавать параметры плагинов. Maven не делает предположений о том, какие параметры могут быть у плагинов. Любая из этих секций может быть пропущена. Так, если параметры по умолчанию устраивают, можно добавить плагин к нужной фазе и всё. И наоборот, если плагин уже автоматически добавлен к какой-либо фазе, можно только указать его новые параметры.
Плагин compiler
Плагин compiler комплирует исходный java код приложения и тестов в байткод. Особенностью плагина являются его настройки по умолчанию: он ожидает, что исходный код должен быть совместим с java версии 1.5 и генерирует байткод для той же самой версии 1.5. Поэтому в каждом проекте приходится вручную выставлять версию кода:
1
2
3
4
5
6
7
8
9
|
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
|
Другая, часто используемая опция этого плагина, это задание ключей компилятора:
1
2
3
4
5
6
7
8
9
10
11
|
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.2</version>
<configuration>
<compilerArgs>
<arg>-verbose</arg>
<arg>-Xlint:all,-options,-path</arg>
</compilerArgs>
</configuration>
</plugin>
|
Плагин, как вы понимаете, сам ничего не компилирует, а вызывает javax.tools.JavaCompiler или javac, в зависимости от параметра forceJavacCompilerUse
Плагин surefire
Этот плагин реализует всю магию по исполнению юнит тестов. По умолчанию он проверяет все классы, начинающиеся словом Test* или наоборот, заканчивающиеся на *Test, *Tests, *TestCase и пытается найти в них тесты и запустить их. Плагин исполняет все найденные тесты и пишет отчёты по каждому запущенному тесту, помещая их в каталог target/surefire-reports. В случае если имеется хотя бы один провалившийся тест, плагин прерывает сборку с ошибкой.
Список классов к запуску может быть изменён и в него могут быть включены дополнительные файлы или наоборот, исключены ненужные:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<includes>
<include>Sample.java</include>
</includes>
<excludes>
<exclude>**/TestCircle.java</exclude>
<exclude>**/TestSquare.java</exclude>
</excludes>
</configuration>
</plugin>
|
Интересной возможностью плагина является возможность исполнения тестов параллельно. Так как юнит-тесты должны быть независимы друг от друга, это, обычно, вполне безопасно и позволяет сократить время исполнения тестов. По умолчанию параллельное исполнение не включено и требует дополнительной настройки:
1
2
3
4
5
6
7
8
9
|
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<parallel>methods</parallel>
<threadCount>10</threadCount>
</configuration>
</plugin>
|
В примере выше я говорю плагину surefire что хочу исполнять параллельно непосредственно тесты (а не, например, классы тестов или наборы тестов) и что хочу ограничиться десятью параллельными нитями исполнения.
Наконец, если тесты проваливаются, а собрать приложение всё таки очень надо, можно указать плагину, что исполнение тестов необходимо пропустить:
1
2
3
4
5
6
7
8
|
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
|
Этого же эффекта можно добиться, используя параметр -DskipTests в коммандной строке maven.
Плагин failsafe
Плагин failsafe — брат близнец плагина surefire и так же занимается исполнением тестов. Но failsafe, в отличие от surefire, исполняет интеграционные тесты, а не модульные. Поэтому он ищет файлы, оканчивающиеся на *IT, *ITCase или начинающиеся на IT*. Отчёты о выполнении тестов пишутся в каталог target/failsafe-reports. Кроме того, опять в отличие от surefire, плагин failsafe не проваливает сборку при ошибках тестов, тем самым позволяя выполниться цели post-integration-test, которая должна очистить окружение.
В остальном поведение плагина и его настройки идентичны предыдущему.
Плагин jar
Плагин jar отвечает за упаковку вашего приложения в jar пакет. Наиболее часто используемая настройка этого плагина — имя выходного файла:
1
2
3
4
5
6
7
8
|
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<finalName>myJar</finalName>
</configuration>
</plugin>
|
Особенностью плагина jar является минималистичность сборки, в которую попадают только классы вашего приложения, без их зависимостей.
Плагин assembly
Плагин assembly был создан для того, чтобы собирать различные артефакты сборки в пакет(ы) для распространения. Например, если у вас есть веб приложение, состоящее из javascript фронтенда и java web приложения на бэкенде, с помощью плагина assembly можно собрать war пакет для сервера и zip архив с кодом клиента.
Но чаще этот плагин используют для решения проблемы с плагином jar — для сборки jar пакета с зависимостями:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
|
Дескриптор jar-with-dependencies поставляется в комплекте с плагином и не требует дополнительной настройки. Так как плагин не встраивается в цикл сборки автоматически, приходится назначать цель сборки вручную.
Сам плагин настраивается дескриптором сборки, который может быть как встроен в плагин, так и написан вручную. Скажем для примера выше, с приложением состоящим из фронтенда и бэкенда, можно было бы использовать следующую конфигурацию плагина:
1
2
3
4
5
6
7
8
9
|
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/static.xml</descriptor>
</descriptors>
</configuration>
</plugin>
|
Со следующим дескриптором:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<assembly>
<id>static</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>src/main/webapp</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>/css/**</include>
<include>/images/**</include>
<include>/js/ext/locale/**</include>
<include>/js/ext/ext.js</include>
<include>/js/App/locale/**</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.build.directory}/sencha</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>/index.html</include>
<include>/all-classes.js</include>
</includes>
</fileSet>
</fileSets>
</assembly>
|
Дескриптор выше взят из реального приложения и собирает все части single page приложения в один архив, при этом используя как сгенерированный javascript код, так и часть исходного кода. В принципе я всего лишь хотел продемонстрировать, насколько гибок assembly плагин.
Вышеприведённый список плагинов конечно же не полный и не покрывает и трети только официальных плагинов, не говоря уже о плагинах сторонних разработчиков. Кроме того, вы можете разрабатывать свои плагины и как это сделать я опишу в следующей статье.