В статье о сборочных циклах я писал, что 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 плагин.
Вышеприведённый список плагинов конечно же не полный и не покрывает и трети только официальных плагинов, не говоря уже о плагинах сторонних разработчиков. Кроме того, вы можете разрабатывать свои плагины и как это сделать я опишу в следующей статье.