Жизненный цикл сборки Maven: фазы, цели плагинов и команды - Вопросы

Всего: 6 вопросов

1. 

Что такое жизненный цикл сборки Maven и какие жизненные циклы встроены в Maven?

Жизненный цикл сборки (build lifecycle) - заранее определённая упорядоченная последовательность фаз, через которые проходит проект: проверка, компиляция, тесты, упаковка, установка и публикация. Реальную работу на фазах делают привязанные к ним цели (goals) плагинов.

В Maven три независимых встроенных цикла:

  • default - 23 фазы от validate до deploy: компиляция, тесты, упаковка, установка в локальный репозиторий, публикация (mvn package, mvn verify, mvn install).
  • clean - фазы pre-clean, clean, post-clean; удаляет каталог target целью clean:clean.
  • site - фазы pre-site, site, post-site, site-deploy; генерирует HTML-сайт проекта с отчётами в target/site (maven-site-plugin, отчёты задаёт раздел <reporting>).

Фаза одного цикла не запускает фазы другого: mvn install не очищает target, а mvn clean ничего не компилирует. Слово clean обозначает и цикл, и его главную фазу, поэтому в старых статьях clean и site ошибочно называют «фазами, стоящими особняком».

Фазы разных циклов можно перечислить в одной команде, и Maven выполнит их слева направо: mvn clean package site - сначала цикл clean до фазы clean, затем default до package, затем site до site.

2. 

Какие фазы есть в жизненном цикле default и что выполняется при запуске mvn package?

В цикле default 23 фазы, но в командах обычно используют семь основных:

  • validate - проверка корректности POM;
  • compile - компиляция основного кода в target/classes (ресурсы копируются перед ней);
  • test - компиляция и запуск unit-тестов (maven-surefire-plugin), упавший тест останавливает сборку;
  • package - упаковка в формат из <packaging> (jar, war);
  • verify - проверки качества и результатов интеграционных тестов;
  • install - копирование артефакта и POM в локальный репозиторий ~/.m2/repository;
  • deploy - публикация в удалённый репозиторий из <distributionManagement>.

Остальные фазы (initialize, generate-sources, process-resources, test-compile, prepare-package, pre-integration-test, integration-test, post-integration-test и др.) - точки, куда плагины встраивают подготовительные шаги; напрямую их почти не вызывают.

Главное правило: mvn <фаза> выполняет все фазы того же цикла от первой до указанной включительно. Поэтому mvn package сам скопирует ресурсы, скомпилирует код и тесты, прогонит тесты и создаст jar, а verify, install и deploy не запустятся. Если тест падает, сборка останавливается на test, и jar не создаётся. Фаза, к которой не привязано ни одной цели, ничего не делает и в логе не видна.

В Maven 4 фазы и команды те же, но вместо pre-* и post-* появились хуки before: и after: для любой фазы (старые имена сохранены).

3. 

Чем фаза отличается от цели (goal) плагина в Maven?

Фаза - шаг жизненного цикла (package), сама по себе она ничего не делает: работу выполняют привязанные к ней цели. Цель - конкретное действие плагина (compiler:compile, jar:jar).

  • При запуске фазы Maven выполняет все предыдущие фазы того же цикла и привязанные к ним цели.
  • При запуске цели выполняется только она одна, без предыдущих шагов.

Синтаксис цели: короткая форма префикс:цель (mvn jar:jar) или полные координаты mvn org.apache.maven.plugins:maven-jar-plugin:3.4.1:jar. Цели вызывают напрямую для разовых действий вне сборки: mvn dependency:tree, mvn help:effective-pom. Фазы и цели можно смешивать: mvn clean compile dependency:tree выполнит цикл clean, затем default до compile и потом цель.

Типичные ошибки: mvn clean jar:jar даёт BUILD SUCCESS, но пустой jar (JAR will be empty) - компиляции не было; mvn surefire:test после правки кода прогоняет тесты по старым .class-файлам. В логе цель, вызванная из командной строки, помечена id выполнения default-cli, а цель из стандартной привязки - default-... (например, default-jar). Для сборки запускайте фазы: mvn clean package, mvn test.

4. 

Как цели плагинов привязываются к фазам жизненного цикла Maven и как посмотреть привязки своего проекта?

Стандартные привязки задаёт элемент <packaging>: для каждого типа упаковки в Maven встроен свой набор (lifecycle mapping). Поэтому jar-проект собирается без единого объявленного плагина.

Привязки для packaging = jar (Maven 3.9.x):

  • process-resources - resources:resources; compile - compiler:compile;
  • process-test-resources - resources:testResources; test-compile - compiler:testCompile;
  • test - surefire:test; package - jar:jar;
  • install - install:install; deploy - deploy:deploy.

У war на фазе package вместо jar:jar выполняется war:war, у pom остаются только install и deploy - компиляции и тестов нет. Свои цели можно привязать к любой фазе в <build><plugins>; если к фазе привязано несколько целей, сначала выполняются стандартные, затем объявленные в pom.xml в порядке объявления. Добавить свою фазу обычно не нужно: цель привязывают к существующей (генератор кода - к generate-sources, проверку стиля - к verify).

Фактические привязки проекта с учётом родителя и версий плагинов показывает mvn help:describe -Dcmd=compile: напротив каждой фазы указана цель или Not defined, если к фазе ничего не привязано.

5. 

Чем maven-surefire-plugin отличается от maven-failsafe-plugin и почему интеграционные тесты запускают командой mvn verify?

  • Surefire запускает unit-тесты на фазе test, подключён по умолчанию. Классы по умолчанию: Test*, *Test, *Tests, *TestCase. Упавший тест сразу останавливает сборку. Отчёты - target/surefire-reports.
  • Failsafe запускает интеграционные тесты, его нужно явно объявить в <build><plugins> с целями integration-test и verify (элемент phase не нужен: фазы по умолчанию совпадают с именами целей). Классы: IT*, *IT, *ITCase. Отчёты - target/failsafe-reports.

Интеграционные тесты идут после package: им нужен собранный артефакт и окружение (база, контейнер, сервер). Запуск окружения привязывают к pre-integration-test, остановку - к post-integration-test. Если IT падает, failsafe не роняет сборку сразу: она доходит до post-integration-test (окружение останавливается) и падает на verify.

Поэтому запускать нужно mvn verify (или install, deploy). Сама фаза integration-test тестов не запускает - это делает привязанная к ней цель failsafe. mvn integration-test останавливается на одноимённой фазе: окружение остаётся запущенным, а failsafe:verify не выполняется, и можно получить BUILD SUCCESS с красными тестами. Класс *IT без failsafe не запускается вообще.

Пропуск: -DskipITs - только интеграционные, -DskipTests - все тесты.

6. 

Какие команды сборки Maven нужны в повседневной работе и чем mvn clean verify отличается от mvn clean install?

  • mvn clean verify - очистка, компиляция, все тесты и проверки; артефакт остаётся в target. Подходит для проверки перед коммитом и на CI.
  • mvn clean install - то же плюс копирование артефакта в ~/.m2/repository. Нужен, когда артефакт должен подхватить другой, отдельно собираемый проект. В многомодульном проекте модули получают результаты соседей внутри одной сборки (reactor), устанавливать их для этого не нужно.
  • mvn package -DskipTests - тесты компилируются, но не запускаются (в логе Tests are skipped.). -Dmaven.test.skip=true не компилирует тесты вовсе: ошибка в тестовом коде останется незамеченной, а test-jar не будет создан, и зависимый от него модуль упадёт. Поэтому предпочтительнее -DskipTests.
  • -pl shop-core -am - модуль и модули, от которых он зависит; -amd - модуль и зависящие от него; -rf :shop-web - продолжить упавшую сборку с модуля.
  • -o - офлайн-режим; -U - принудительная проверка обновлений SNAPSHOT-зависимостей.
  • mvn test -Dtest=OrderServiceTest#create - один тестовый класс или метод; для интеграционных - mvn verify -Dit.test=OrderRepositoryIT.

clean перед каждой сборкой не обязателен: он нужен после удаления или переименования классов, смены версии Java или плагинов и на CI.

Страница 1 из 1