Maven ·
‹ Предыдущий Следующий ›
⏱ 5 минут чтения Обновлено: 2026-11-07

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

Команда mvn clean jar:jar завершается BUILD SUCCESS, а в каталоге target появляется shop-1.0-SNAPSHOT.jar. Только классов в нём нет, а в логе стоит предупреждение JAR will be empty - no content was marked for inclusion!. Причина в том, что jar:jar — это цель плагина, а не фаза: Maven выполнил ровно её и не стал компилировать код. Команда mvn clean package дала бы рабочий jar, потому что фаза package тянет за собой все предыдущие этапы сборки.

Жизненный цикл сборки Maven (build lifecycle) — это заранее определённая упорядоченная последовательность фаз, через которые проходит проект: проверка, компиляция, тесты, упаковка, установка и публикация. В Maven три встроенных жизненных цикла: default (сборка), clean (очистка) и site (сайт проекта). Когда вы запускаете фазу, например mvn package, Maven выполняет все фазы этого цикла до неё включительно, а реальную работу на каждой фазе делают привязанные к ней цели (goals) плагинов.

Три жизненных цикла: default, clean, site

В Maven встроено три независимых жизненных цикла: default собирает проект от проверки POM до публикации артефакта, clean удаляет результаты прошлой сборки, site генерирует сайт проекта с отчётами. Фаза одного цикла не запускает фазы другого: mvn install не очищает target, а mvn clean ничего не компилирует.

Жизненный цикл Фазы (по порядку) Что делает Типичная команда
default 23 фазы от validate до deploy (см. ниже) Компиляция, тесты, упаковка, установка в локальный репозиторий, публикация mvn package, mvn verify, mvn install
clean pre-clean, clean, post-clean Удаляет каталог сборки (target) целью clean:clean mvn clean
site pre-site, site, post-site, site-deploy Генерирует HTML-сайт проекта с отчётами (Javadoc, тесты, анализ кода) в target/site; site-deploy публикует его на сервер mvn site

Слово clean обозначает и сам жизненный цикл, и его главную фазу, отсюда путаница в старых статьях, где clean и site называют «фазами, стоящими особняком». Точнее так: это отдельные циклы, которые выполняются, только если их фаза явно указана в команде. Для mvn site используется maven-site-plugin, а какие отчёты попадут на сайт, задаёт раздел <reporting> в pom.xml.

В одной команде можно перечислить фазы разных циклов — Maven выполнит их слева направо:

mvn clean package site

Здесь сначала отработает цикл clean до фазы clean, затем default до package, затем site до site: проект собирается «с нуля» и получает сайт с документацией.

Фазы жизненного цикла default

Жизненный цикл default состоит из 23 фаз, но в командах обычно используют семь основных: validate, compile, test, package, verify, install и deploy. Остальные фазы — промежуточные точки, к которым плагины привязывают подготовительные шаги: генерацию кода, копирование ресурсов, запуск окружения для интеграционных тестов.

Фаза Что происходит Результат
validate Проверка, что POM корректен и вся нужная информация есть Ошибка, если в pom.xml нет обязательных элементов
compile Компиляция основного кода (перед ней копируются ресурсы) .class-файлы в target/classes
test Компиляция и запуск unit-тестов плагином maven-surefire-plugin Отчёты в target/surefire-reports; упавший тест останавливает сборку
package Упаковка скомпилированного кода в формат из <packaging> target/shop-1.0-SNAPSHOT.jar (или .war)
verify Проверки качества и результатов интеграционных тестов (если к фазе привязаны плагины) Сборка падает, если проверка не прошла
install Копирование артефакта и POM в локальный репозиторий ~/.m2/repository Другие проекты на этой машине могут подключить его как зависимость
deploy Публикация артефакта в удалённый репозиторий из <distributionManagement> Артефакт доступен команде и CI-серверам

Полный порядок фаз default (Maven 3), основные выделены в таблице выше:

validate -> initialize
-> generate-sources -> process-sources -> generate-resources -> process-resources
-> compile -> process-classes
-> generate-test-sources -> process-test-sources -> generate-test-resources -> process-test-resources
-> test-compile -> process-test-classes -> test
-> prepare-package -> package
-> pre-integration-test -> integration-test -> post-integration-test
-> verify -> install -> deploy

Фазы с префиксами pre-, post- и process- напрямую почти никогда не вызывают: они нужны, чтобы плагин мог встроиться в правильное место сборки. Фаза, к которой не привязано ни одной цели, ничего не делает — например, для простого jar-проекта mvn validate только прочитает и проверит POM и выведет BUILD SUCCESS. Как install раскладывает файлы по каталогам локального репозитория, разобрано в уроке Виды репозиториев в Maven.

Запуск фазы выполняет все предыдущие

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

mvn package

В выводе Maven каждая выполненная цель отмечена строкой вида --- plugin:version:goal (execution-id) @ project ---, и по ним видно, что произошло на самом деле. Вывод (фрагмент, Maven 3.9; версии плагинов зависят от версии Maven):

[INFO] --- resources:3.3.1:resources (default-resources) @ shop ---
[INFO] --- compiler:3.13.0:compile (default-compile) @ shop ---
[INFO] --- resources:3.3.1:testResources (default-testResources) @ shop ---
[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ shop ---
[INFO] --- surefire:3.5.2:test (default-test) @ shop ---
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] --- jar:3.4.1:jar (default-jar) @ shop ---
[INFO] Building jar: /home/user/shop/target/shop-1.0-SNAPSHOT.jar
[INFO] BUILD SUCCESS

Фазы без привязанных целей (validate, initialize, generate-sources, prepare-package и другие) в логе не упоминаются: для jar-проекта на них ничего не выполняется. Префикс default- в скобках означает, что цель пришла из стандартной привязки, а не из вашего pom.xml. Если тест падает, Maven останавливается на фазе test, и jar не создаётся.

Команда mvn deploy пройдёт все фазы default, но в учебном проекте завершится ошибкой на последней: не указано, куда публиковать.

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:3.1.2:deploy (default-deploy) on project shop:
Deployment failed: repository element was not specified in the POM inside distributionManagement element
or in -DaltDeploymentRepository=id::url parameter

Фаза и цель (goal): в чём разница

Фаза — это шаг жизненного цикла, сама по себе она ничего не делает. Цель (goal) — конкретное действие плагина, например compiler:compile или jar:jar. При запуске фазы Maven выполняет все предыдущие фазы того же цикла и привязанные к ним цели. При запуске цели выполняется только она одна, без предыдущих шагов.

Признак Фаза Цель (goal)
Пример package jar:jar
Кто выполняет работу Цели, привязанные к фазе Плагин (maven-jar-plugin)
Что выполняется при запуске Все фазы цикла до неё включительно Только эта цель
Синтаксис mvn package mvn jar:jar или mvn org.apache.maven.plugins:maven-jar-plugin:3.4.1:jar

Короткая форма jar:jar — это префикс плагина и имя цели. Цели вызывают напрямую для разовых действий, которые не входят в сборку: mvn dependency:tree, mvn help:effective-pom, mvn versions:display-dependency-updates. Фазы и цели можно смешивать в одной команде: mvn clean compile dependency:tree выполнит цикл clean, затем default до compile и только потом цель dependency:tree.

Отсюда ошибка из начала урока: mvn clean jar:jar удалил target и сразу упаковал несуществующий каталог классов. Вывод:

[INFO] --- clean:3.2.0:clean (default-clean) @ shop ---
[INFO] Deleting /home/user/shop/target
[INFO] --- jar:3.4.1:jar (default-cli) @ shop ---
[WARNING] JAR will be empty - no content was marked for inclusion!
[INFO] Building jar: /home/user/shop/target/shop-1.0-SNAPSHOT.jar
[INFO] BUILD SUCCESS

Id выполнения default-cli показывает, что цель вызвана из командной строки, а не фазой. Чтобы собрать jar, запускайте фазу: mvn clean package.

Привязка целей плагинов к фазам

Какие цели выполняются на каждой фазе, определяет элемент <packaging> в pom.xml: для каждого типа упаковки в Maven встроен свой набор стандартных привязок (lifecycle mapping). Поэтому jar-проект собирается без единого объявленного плагина, а war и pom на тех же фазах делают другое. Свои цели можно привязать к любой фазе в разделе <build><plugins>.

Стандартные привязки для packaging = jar (Maven 3.9.x):

Фаза Цель плагина Что делает
process-resources resources:resources Копирует src/main/resources в target/classes
compile compiler:compile Компилирует src/main/java
process-test-resources resources:testResources Копирует src/test/resources в target/test-classes
test-compile compiler:testCompile Компилирует src/test/java
test surefire:test Запускает unit-тесты
package jar:jar Создаёт jar в target
install install:install Копирует jar и POM в ~/.m2/repository
deploy deploy:deploy Публикует в удалённый репозиторий

У war на фазе package вместо jar:jar выполняется war:war. У pom (родительские и агрегирующие POM) остаются только install и deploy: компиляции и тестов нет. Как значение packaging задаётся и на что ещё влияет, описано в разделе Элемент packaging, а как привязать к фазе свою цель через <executions> — в уроке Использование плагинов в Maven. Если к одной фазе привязано несколько целей, сначала выполняются цели из стандартной привязки, затем объявленные в pom.xml — в порядке объявления.

Таблица выше справедлива для «чистого» проекта. Проверить фактические привязки вашего проекта (с учётом родителя и версий плагинов) можно командой mvn help:describe:

mvn help:describe -Dcmd=compile

Вывод (фрагмент):

[INFO] 'compile' is a phase corresponding to this plugin:
org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile

It is a part of the lifecycle for the POM packaging 'jar'. This lifecycle includes the following phases:
* validate: Not defined
* initialize: Not defined
...
* process-resources: org.apache.maven.plugins:maven-resources-plugin:3.3.1:resources
* compile: org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile
...
* test: org.apache.maven.plugins:maven-surefire-plugin:3.5.2:test
* package: org.apache.maven.plugins:maven-jar-plugin:3.4.1:jar

Not defined означает, что к фазе ничего не привязано. Описание целей конкретного плагина выводит mvn help:describe -Dplugin=surefire -Ddetail. Официальный список фаз и привязок — в документации Introduction to the Build Lifecycle.

Unit- и интеграционные тесты: surefire и failsafe

Unit-тесты запускает maven-surefire-plugin на фазе test, он подключён по умолчанию. Интеграционные тесты запускает maven-failsafe-plugin: его нужно объявить в pom.xml. Он работает на фазах integration-test и verify, поэтому интеграционные тесты запускают командой mvn verify, а не mvn integration-test.

Признак Surefire (unit-тесты) Failsafe (интеграционные тесты)
Подключение По умолчанию, привязан к фазе test Только явно в <build><plugins>
Фазы test integration-test (запуск) и verify (проверка результата)
Имена классов по умолчанию Test*, *Test, *Tests, *TestCase IT*, *IT, *ITCase
Если тест упал Сборка сразу останавливается на test Сборка доходит до post-integration-test (окружение успевает остановиться) и падает на verify
Отчёты target/surefire-reports target/failsafe-reports
Пропустить -DskipTests -DskipITs (только интеграционные) или -DskipTests (все)

Интеграционные тесты выполняются после package, так как им часто нужен собранный артефакт и внешнее окружение: база данных, контейнер, поднятый сервер. Запуск окружения привязывают к pre-integration-test, остановку — к post-integration-test. Минимальное подключение failsafe:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>3.5.2</version>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Элемент <phase> здесь не нужен: у целей failsafe есть фазы по умолчанию, совпадающие с их именами. Вывод mvn verify для проекта с классом OrderRepositoryIT (фрагмент):

[INFO] --- surefire:3.5.2:test (default-test) @ shop ---
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] --- jar:3.4.1:jar (default-jar) @ shop ---
[INFO] --- failsafe:3.5.2:integration-test (default) @ shop ---
[INFO] Running com.examclouds.shop.OrderRepositoryIT
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] --- failsafe:3.5.2:verify (default) @ shop ---
[INFO] BUILD SUCCESS

Подробности настройки — в документации Maven Failsafe Plugin. Где хранить тестовые классы и ресурсы, показано в разделе Структура Maven-проекта.

Почему не mvn integration-test

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

Основные команды сборки

В повседневной работе хватает нескольких команд: mvn clean verify — полная проверка проекта, mvn clean install — то же плюс установка в локальный репозиторий, -DskipTests — сборка без запуска тестов, -pl — сборка отдельных модулей многомодульного проекта.

Команда Что делает Когда использовать
mvn clean verify Очистка, компиляция, все тесты и проверки; артефакт остаётся в target Проверка перед коммитом, сборка на CI
mvn clean install То же плюс копирование артефакта в ~/.m2/repository Когда собранный модуль нужен другому проекту на этой машине
mvn package -DskipTests Тесты компилируются, но не запускаются; в логе Tests are skipped. Быстро получить jar, когда тесты уже проверены
mvn package -Dmaven.test.skip=true Тесты не компилируются и не запускаются Редко: если тестовый код временно не компилируется
mvn -pl shop-core -am install Собирает модуль shop-core и модули, от которых он зависит (-am, also make) Многомодульный проект, нужен один модуль
mvn -pl shop-core -amd verify Собирает модуль и модули, которые зависят от него (-amd) Проверить, что изменение не сломало зависимые модули
mvn verify -rf :shop-web Продолжает упавшую сборку с модуля shop-web (resume from) После исправления ошибки в середине многомодульной сборки
mvn -o package / mvn -U package Офлайн-режим / принудительная проверка обновлений SNAPSHOT-зависимостей Нет сети / нужна свежая SNAPSHOT-версия из удалённого репозитория
mvn package -DskipTests

Вывод (фрагмент):

[INFO] --- surefire:3.5.2:test (default-test) @ shop ---
[INFO] Tests are skipped.
[INFO] --- jar:3.4.1:jar (default-jar) @ shop ---
[INFO] BUILD SUCCESS

Флаг -DskipTests предпочтительнее -Dmaven.test.skip=true: тестовый код хотя бы компилируется, и ошибка в нём не останется незамеченной. Кроме того, если другой модуль подключает ваши тестовые классы как test-jar, с maven.test.skip этот jar не будет создан, и сборка зависимого модуля упадёт на разрешении зависимости. Ключ -pl принимает путь к каталогу модуля или :artifactId, несколько модулей перечисляются через запятую.

mvn clean install по привычке

mvn clean install пишут почти рефлекторно, но для проверки проекта достаточно mvn clean verify: выполняются те же тесты и проверки, а локальный репозиторий не засоряется промежуточными сборками. В многомодульном проекте Maven сам передаёт модулям результаты соседних модулей внутри одной сборки (reactor), устанавливать их в ~/.m2 для этого не нужно. install нужен, когда артефакт должен подхватить другой, отдельно собираемый проект.

Что меняется в Maven 4

В Maven 4 (на ноябрь 2026 года в стадии preview, рекомендуемой остаётся ветка 3.x) жизненный цикл совместим с Maven 3: те же фазы и команды mvn clean verify и mvn install. Главное изменение — вместо фаз pre-* и post-* появились хуки before: и after: для любой фазы (например, before:integration-test), а старые имена сохранены для совместимости.

Для учебных проектов на Maven 3.9.x и 3.10.x всё, что описано в уроке, работает без изменений. Какая версия Maven установлена, показывает mvn -version, а зафиксировать её для всей команды помогает Maven Wrapper (см. урок Что такое Maven).

На чём чаще всего спотыкаются

Ошибки с жизненным циклом редко выглядят как ошибки: сборка проходит, но выполнено не то, что ожидалось. В таблице — что запустили, что получили и как исправить.

Что сделали Что произойдёт Как исправить
mvn clean jar:jar вместо mvn clean package BUILD SUCCESS, но jar без классов; JAR will be empty в логе Запускать фазу, а не цель: mvn clean package
Создали OrderRepositoryIT, но не подключили failsafe Тест не запускается нигде: surefire не берёт *IT, а failsafe нет Объявить maven-failsafe-plugin с целями integration-test и verify
mvn integration-test Окружение тестов не останавливается, упавшие IT не роняют сборку mvn verify
mvn surefire:test после правки кода Тесты идут по старым .class-файлам: компиляции не было mvn test
mvn deploy в проекте без <distributionManagement> Deployment failed: repository element was not specified in the POM inside distributionManagement element Для локальной проверки достаточно verify или install; для публикации указать репозиторий
-Dmaven.test.skip=true в проекте с test-jar Зависимый модуль не находит тестовый jar Использовать -DskipTests
Удалили или переименовали класс и собрали без clean Старый .class может остаться в target/classes и попасть в jar mvn clean package

Часто задаваемые вопросы

Нужно ли запускать mvn clean перед каждой сборкой?

Нет. Компилятор сам пересобирает изменённые классы, и без clean сборка быстрее. clean нужен, когда классы удалялись или переименовывались (их старые .class могут остаться в target), после смены версии Java или плагинов, а также на CI, где сборка всегда должна идти с нуля.

Как запустить только один тестовый класс или метод?

Параметром surefire -Dtest: mvn test -Dtest=OrderServiceTest или mvn test -Dtest=OrderServiceTest#create, допускаются шаблоны (-Dtest=Order*Test). Для интеграционных тестов то же делает -Dit.test=OrderRepositoryIT с командой mvn verify. В многомодульном проекте добавьте -Dsurefire.failIfNoSpecifiedTests=false, иначе модули без такого теста завершатся ошибкой.

Можно ли добавить в жизненный цикл свою фазу?

Обычно в этом нет необходимости: свою цель привязывают к одной из существующих фаз, например запуск генератора кода — к generate-sources, проверку стиля — к verify. Собственный жизненный цикл или тип packaging можно описать только в расширении Maven (extension), это задача авторов плагинов. Как привязать цель к фазе, показано в уроке Использование плагинов в Maven.

Почему mvn install в одном проекте не обновляет зависимость в другом?

Чаще всего версии не совпадают: второй проект ссылается в <dependency> на другую версию, чем та, что указана в pom.xml первого. Если версии совпадают, IDE могла не переимпортировать проект — обновите Maven-проект в IDE. Для SNAPSHOT из удалённого репозитория используйте mvn -U. Куда именно install кладёт файлы, разобрано в уроке Виды репозиториев в Maven.

Практика по теме

Закрепите урок на задачах — у каждой есть уровень и оценка времени.

Все задачи модуля →

Комментарии

vijay_jogi Feb 28, 2017
It is a logical grouping of persistence unit.

Зарегистрируйтесь или войдите, чтобы иметь возможность оставить комментарий.