Жизненный цикл сборки Maven
Изучите три жизненных цикла Maven и основные фазы — validate, compile, test, package, verify, install, deploy — и как цели плагинов привязываются к ним.
Жизненный цикл — центральная идея Maven: сборка проекта — это не произвольный набор задач, а упорядоченная последовательность хорошо известных фаз. Когда вы вводите mvn package, вы не называете одно действие — вы просите Maven выполнить каждую фазу вплоть до package включительно, по порядку. Понимание этой последовательности и того, как цели плагинов привязываются к ней, — это разница между слепым копированием команд и реальным пониманием того, что делает ваша сборка.
Три жизненных цикла, и тот, который вы используете чаще всего
Maven поставляется с тремя встроенными жизненными циклами. Они независимы — вызов фазы одного не запускает другой.
| Жизненный цикл | Назначение | Ключевые фазы |
|---|---|---|
clean | Удалить результаты сборки | pre-clean, clean, post-clean |
default | Собрать и развернуть проект | validate … compile … test … package … install … deploy |
site | Сгенерировать документацию проекта | pre-site, site, site-deploy |
Жизненный цикл default — это место, где происходит основная работа. Команда mvn clean install, которую вы повсюду видите, — это просто два жизненных цикла в одной команде: фаза clean из цикла clean, а затем фаза install из цикла default.
Фазы жизненного цикла default
Жизненный цикл default состоит из 23 фаз, но семь из них несут основную нагрузку почти в каждой сборке. Они всегда выполняются в таком порядке:
| Фаза | Что делает |
|---|---|
validate | Проверяет корректность проекта и наличие всей необходимой информации |
compile | Компилирует исходный код проекта |
test | Запускает модульные тесты с помощью подходящего фреймворка (не требует упаковки) |
package | Упаковывает скомпилированный код в дистрибутивный формат, например JAR |
verify | Выполняет проверки результатов интеграционных тестов для подтверждения качества |
install | Копирует пакет в локальный репозиторий (~/.m2) для других локальных проектов |
deploy | Загружает пакет в удалённый репозиторий для совместного использования |
Правило, которое управляет всем: запуск фазы запускает эту фазу и все предшествующие ей. Так, mvn package незаметно сначала выполнит validate, compile и test. Нет способа «перепрыгнуть» — можно только остановиться раньше.
mvn validate # just the sanity checks
mvn compile # validate -> compile
mvn test # validate -> compile -> test
mvn package # ... -> test -> package (produces target/app-1.0.jar)
mvn install # ... -> package -> verify -> install (now in ~/.m2)
mvn deploy # the full pipeline, ending with an uploadФазы пусты, пока плагины не привяжут к ним цели
Фаза — это просто имя и позиция в последовательности, она сама по себе не выполняет никакой работы. Работу выполняют цели плагинов, привязанные к фазам. Цель записывается как plugin:goal, например compiler:compile. Для проекта, у которого <packaging> равен jar, Maven предоставляет разумный набор привязок по умолчанию:
| Фаза | Цель по умолчанию |
|---|---|
compile | maven-compiler-plugin:compile |
test | maven-surefire-plugin:test |
package | maven-jar-plugin:jar |
install | maven-install-plugin:install |
deploy | maven-deploy-plugin:deploy |
Вы можете добавлять собственные привязки в pom.xml. Здесь плагин exec привязан к фазе verify, чтобы он автоматически запускался ближе к концу сборки:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>smoke-test</id>
<phase>verify</phase>
<goals><goal>java</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>Вы также можете вызвать цель напрямую, вне какой-либо фазы — mvn compiler:compile запускает только эту цель, полностью минуя жизненный цикл. Это иногда бывает полезно, но в повседневной работе вы вызываете фазы и позволяете привязкам срабатывать.
Практический пример: моделирование жизненного цикла
Maven сам по себе не установлен на этом исполнителе, поэтому мы моделируем жизненный цикл на чистом Java, чтобы сделать его правила конкретными. Программа перечисляет фазы по умолчанию, записывает привязанный к каждой plugin:goal, затем «запускает» mvn install — выполняя каждую фазу от validate до install и доказывая, что deploy и clean не включаются.
Что следует вынести из этого запуска:
- Вывод начинается с
validateи заканчивается наinstall— шесть фаз для одной команды. Это накопительное правило в действии:mvn install— это сокращение для выполнения всего префикса последовательности вплоть доinstall, а не только одной именованной фазы. - Каждая выполненная фаза вывела привязанный к ней
plugin:goal(compile -> compiler:compile,package -> jar:jarи так далее). Фазы — это слоты; цели — это то, что фактически компилирует, тестирует и упаковывает.validateвывела(no goal bound), показывая, что фаза может запускаться, не делая ничего. deploy skipped : trueподтверждает, что фазы после запрошенной никогда не выполняются. Чтобы опубликовать в удалённый репозиторий, нужно явно запроситьmvn deploy; обычныйinstallнамеренно остаётся локальным.clean ran : falseдоказывает, чтоcleanпринадлежит отдельному жизненному циклу. Вызовinstallне удаляетtarget/, именно поэтомуmvn clean installявно указывает оба — по одной фазе из каждого жизненного цикла.- Фазы выполнялись в фиксированном порядке
validate, compile, test, package, verify, install, и программа завершилась сBUILD SUCCESS. Порядок не является предметом переговоров; обещание Maven «соглашение важнее конфигурации» основано именно на этой гарантированной повторяемой последовательности.
Распространённые команды на практике
Несколько вызовов покрывают почти всю повседневную работу:
mvn clean # delete target/
mvn test # build and run unit tests
mvn package -DskipTests # build the JAR without running tests
mvn clean install # fresh build, install to local ~/.m2
mvn clean verify # CI's favourite: build + unit + integration checks-DskipTests компилирует тесты, но не запускает их; -Dmaven.test.skip=true также пропускает их компиляцию. Используйте первый вариант, когда тесты медленные, но должны компилироваться, второй — только когда вы действительно хотите полностью исключить их.
Что изучить дальше
- Только знакомитесь с инструментом? Начните со введения в Maven, затем прочитайте, как POM объявляет плагины и привязки.
- Фазы
compileиpackageуспешно выполняются только после разрешения зависимостей проекта — см. управление зависимостями. - Предпочитаете модель графа задач вместо фиксированной последовательности фаз? Сравните с введением в Gradle.