Команды Maven: шпаргалка mvn с примерами и частые ошибки
Перед коммитом разработчик по привычке запускает mvn clean install -DskipTests и видит BUILD SUCCESS. Проверки, ради которой команду запускали, не было: тесты пропущены, зато в ~/.m2/repository установлен jar с непроверенным кодом, и проект, зависящий от этой SNAPSHOT-версии, подхватит его при следующей сборке. Для проверки перед коммитом нужна mvn verify, а clean — не каждый раз, а когда в target могли остаться следы удалённых классов.
Команда mvn — это запуск Maven из командной строки в формате mvn [ключи] [фазы и цели]. Фаза (compile, package, verify) выполняет жизненный цикл до себя включительно, цель плагина в форме префикс:цель (dependency:tree) — одно действие плагина без предыдущих шагов, а ключи (-U, -o, -pl, -D) меняют режим работы. Ниже — шпаргалка (cheat sheet) по командам всего модуля со ссылками на подробные уроки и таблица частых ошибок. Примеры рассчитаны на Maven 3.9.x.
Синтаксис mvn: фазы, цели и ключи
Команда Maven состоит из ключей и списка фаз и целей, которые выполняются слева направо. Фаза запускает все предыдущие фазы своего жизненного цикла, цель — только саму себя. Цель записывают через префикс плагина (dependency:tree) или полными координатами groupId:artifactId[:version]:goal.
| Форма | Пример | Что выполнится |
|---|---|---|
| Фаза | mvn verify | Все фазы default от validate до verify |
| Несколько фаз | mvn clean verify | Цикл clean, затем default до verify |
| Цель через префикс | mvn dependency:tree | Только цель tree плагина maven-dependency-plugin |
| Цель по координатам | mvn org.apache.maven.plugins:maven-dependency-plugin:3.8.1:tree | Та же цель ровно указанной версии плагина |
| Фазы и цели вместе | mvn clean compile dependency:tree | Сначала фазы, потом цель — в порядке записи |
| Параметр плагина | mvn test -Dtest=OrderServiceTest | Фаза test; свойство test читает Surefire |
Короткие префиксы Maven по умолчанию ищет в группах org.apache.maven.plugins и org.codehaus.mojo, поэтому работают exec:java и versions:... без объявления в pom.xml. Если сборка упала, mvn завершается с ненулевым кодом выхода — на этом построены CI-скрипты. Разница фазы и цели с примером пустого jar — в разделе Фаза и цель (goal), формы вызова плагина — в разделе Плагин и цель.
Сборка: clean, package, verify, install
Для ежедневной сборки хватает фаз compile, test, package и verify: последняя прогоняет все тесты и проверки и оставляет артефакт в target. install нужен, только когда артефакт должен увидеть другой проект на этой машине, deploy — для публикации в удалённый репозиторий.
| Команда | Что делает и когда использовать | Подробнее |
|---|---|---|
mvn clean | Удаляет target. Нужна после удаления или переименования классов, смены JDK или версий плагинов и на CI | Три жизненных цикла |
mvn compile | Копирует ресурсы и компилирует src/main/java в target/classes | Фазы default |
mvn test | Компилирует и запускает unit-тесты (Surefire); упавший тест останавливает сборку | surefire и failsafe |
mvn package | Всё до тестов включительно плюс упаковка в jar/war в target | Порядок фаз |
mvn verify | Плюс интеграционные тесты (failsafe) и проверки качества, если эти плагины подключены. Команда для проверки перед коммитом и на CI | Основные команды |
mvn install | Плюс копирование jar и POM в ~/.m2/repository для других проектов на этой машине. К установке самого Maven отношения не имеет | Установка Maven и mvn install |
mvn deploy | Плюс публикация в репозиторий из <distributionManagement> (Nexus, Artifactory) | install и deploy |
mvn site | Сайт проекта с отчётами в target/site (отдельный цикл site) | Цикл site |
mvn clean install | Сборка «с нуля» с установкой в ~/.m2. Для проверки проекта обычно достаточно mvn clean verify | clean install или verify |
Многомодульному проекту install для связи модулей не нужен: внутри одной сборки reactor передаёт модулям результаты соседей напрямую (Агрегация и reactor).
Тесты: пропуск и запуск отдельных тестов
Чтобы пропустить тесты, используют -DskipTests: тестовый код компилируется, но не запускается. -Dmaven.test.skip=true не компилирует тесты вовсе и нужен редко. Отдельный класс или метод запускают параметром Surefire -Dtest, интеграционный тест — параметром failsafe -Dit.test.
| Команда | Что делает и когда использовать | Подробнее |
|---|---|---|
mvn package -DskipTests | Тесты компилируются, но не запускаются; в логе Tests are skipped. | Основные команды |
mvn package -Dmaven.test.skip=true | Тесты не компилируются; не создаётся и test-jar, от которого может зависеть другой модуль | |
mvn verify -DskipITs | Пропускает только интеграционные тесты failsafe | surefire и failsafe |
mvn verify -Dit.test=OrderRepositoryIT | Один интеграционный тест | |
mvn test -Dtest=OrderServiceTest | Один тестовый класс | FAQ: один тест |
mvn test -Dtest=OrderServiceTest#create | Один метод; несколько — через +: #create+cancel | |
mvn test -Dtest='Order*Test' | По шаблону; кавычки — чтобы * не раскрыла оболочка | |
-Dsurefire.failIfNoSpecifiedTests=false | С -Dtest в многомодульном проекте: модули без такого теста не падают. Старый совет -DfailIfNoTests=false в новых версиях Surefire для этого случая может не сработать | Команды reactor |
mvn verify -Dmaven.test.failure.ignore=true | Тесты выполняются, но упавшие не останавливают сборку (отчёты остаются в target/surefire-reports) | surefire и failsafe |
Запуск приложения
Maven собирает приложение, но запускать его удобнее обычной командой java. Для быстрого запуска из исходников подходит цель exec:java плагина exec-maven-plugin (MojoHaus, org.codehaus.mojo): она выполняет метод main внутри JVM самого Maven с classpath проекта.
| Команда | Что делает и когда использовать | Подробнее |
|---|---|---|
mvn compile exec:java -Dexec.mainClass=com.examclouds.App | Компилирует и запускает main; аргументы — -Dexec.args="a b". Без compile цель возьмёт старые классы из target | Обзор плагинов |
java -cp target/hello-maven-1.0-SNAPSHOT.jar com.examclouds.App | Запуск после mvn package с явным главным классом; библиотеки зависимостей тоже перечисляют в -cp | Первая сборка и запуск |
java -jar target/hello-maven-1.0-SNAPSHOT.jar | Работает, только если в манифесте есть Main-Class, иначе no main manifest attribute. Обычный jar не содержит зависимостей | Исполняемый jar |
Зависимости и обновления версий
Команды для зависимостей дают два плагина: maven-dependency-plugin (дерево, анализ, загрузка, очистка локального репозитория) и versions-maven-plugin от MojoHaus (поиск новых версий библиотек и плагинов). Ни одна из этих целей не меняет pom.xml, кроме versions:set и других целей versions, которые явно правят версии.
| Команда | Что делает и когда использовать | Подробнее |
|---|---|---|
mvn dependency:tree | Дерево зависимостей с транзитивными — первое, что смотрят при конфликте версий | dependency:tree и analyze |
mvn dependency:tree -Dverbose | Показывает и проигравшие версии (omitted for conflict); поддержка и формат зависят от версии плагина | |
mvn dependency:tree -Dincludes=com.google.guava | Только ветки с нужной библиотекой (groupId[:artifactId]) | |
mvn dependency:analyze | Используемые, но не объявленные и объявленные, но неиспользуемые зависимости (эвристика по байткоду) | |
mvn dependency:resolve | Скачивает и печатает список зависимостей проекта со scope | Scope |
mvn dependency:go-offline | Заранее скачивает зависимости и плагины для работы с -o; не гарантирует, что скачается всё, что плагины подгружают во время сборки | Локальный репозиторий |
mvn dependency:purge-local-repository | Удаляет зависимости проекта из ~/.m2 и по умолчанию скачивает заново — при «битых» файлах | |
mvn versions:display-dependency-updates | Список зависимостей, для которых есть новые версии | dependencyManagement |
mvn versions:display-plugin-updates | То же для плагинов, плюс плагины без зафиксированной версии | Версии плагинов |
mvn versions:set -DnewVersion=1.1-SNAPSHOT | Меняет версию проекта во всех модулях | Версия проекта |
Диагностика: плагин help
Когда сборка ведёт себя неожиданно, сначала смотрят, что Maven реально получил на вход: итоговый POM, настройки, активные профили и привязки целей. Всё это показывает maven-help-plugin, и ни одна его цель не запускает сборку.
| Команда | Что показывает | Подробнее |
|---|---|---|
mvn help:effective-pom | Итоговый POM после наследования, профилей и подстановки свойств; в файл — -Doutput=effective.xml | Super POM и effective POM |
mvn help:effective-settings | Итоговый settings.xml (пользовательский + глобальный), пароли скрыты | settings.xml |
mvn help:active-profiles | Активные профили каждого модуля и их источник | help:active-profiles |
mvn help:all-profiles | Все объявленные профили с признаком активности | |
mvn help:describe -Dplugin=compiler -Ddetail | Цели плагина и их параметры (с именами свойств для -D) | Настройка плагина |
mvn help:describe -Dcmd=compile | Какие цели привязаны к фазам для вашего packaging | Привязка целей |
mvn help:evaluate -Dexpression=project.version -q -DforceStdout | Значение выражения: версия, project.artifactId, свойство из <properties> | Свойства |
Пример для скрипта сборки (параметр forceStdout есть в maven-help-plugin 3.1.0 и новее):
VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
echo "$VERSION"
# Output: 1.0-SNAPSHOT Неочевидный момент: help:evaluate без -q
Без -q в переменную VERSION попадёт весь лог Maven со строками [INFO], а без -DforceStdout при -q значение не выведется вовсе. Если в выводе всё же есть строки Downloading, добавьте -B -ntp или выполните команду один раз заранее, чтобы плагин уже лежал в ~/.m2.
Многомодульный проект
В многомодульном проекте команды запускают из корня, а часть модулей выбирают ключами reactor: -pl — какие модули, -am — плюс модули, от которых они зависят, -amd — плюс модули, которые зависят от них. Без -am соседние модули берутся из ~/.m2, то есть в старой версии.
| Команда | Что делает и когда использовать | Подробнее |
|---|---|---|
mvn -pl shop-web -am package | Модуль и всё, от чего он зависит | Команды reactor |
mvn -pl shop-model -amd verify | Модуль и всё, что от него зависит — проверить потребителей после правки | |
mvn verify -rf :shop-web | Продолжить упавшую сборку с модуля (Maven сам подсказывает эту команду) | |
mvn -pl '!shop-web' verify | Все модули, кроме указанного (с Maven 3.2.1) | |
mvn -T 1C verify | Параллельная сборка независимых модулей: 1 поток на ядро | |
mvn -f shop-web/pom.xml package | Сборка указанного POM без захода в каталог; reactor корня не участвует, как при cd shop-web | Агрегация и reactor |
mvn -N install | Только корневой POM без модулей (non-recursive) — например, установить родителя | Наследование: parent POM |
Создание проекта и Maven Wrapper
Новый проект создают целью archetype:generate, а версию Maven для всей команды фиксируют Maven Wrapper: после mvn wrapper:wrapper проект собирают скриптом ./mvnw, который сам скачивает нужную версию Maven.
| Команда | Что делает и когда использовать | Подробнее |
|---|---|---|
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DgroupId=com.examclouds -DartifactId=hello-maven -DinteractiveMode=false | Проект из шаблона quickstart без вопросов в консоли; в PowerShell каждый -D... берут в кавычки | archetype:generate |
mvn wrapper:wrapper | Добавляет mvnw, mvnw.cmd и .mvn/wrapper/maven-wrapper.properties; версию можно задать, например, -Dmaven=3.9.11 | Maven Wrapper |
./mvnw clean verify (Windows: mvnw.cmd clean verify) | Те же команды и ключи, что у mvn, но зафиксированной версией Maven; JDK Wrapper не фиксирует | |
mvn -v | Версия Maven, путь установки, версия и путь JDK, ОС | Проверка установки |
Полезные ключи mvn
Ключи пишут до или после фаз в любом порядке. Для CI типичный набор — -B (без интерактивных вопросов и цветного вывода) и -ntp (без строк о скачивании): mvn -B -ntp clean verify. Полный список выводит mvn -h.
| Ключ | Длинная форма | Что делает |
|---|---|---|
-U | --update-snapshots | Принудительно проверяет обновления SNAPSHOT и сбрасывает закэшированные неудачные попытки загрузки |
-o | --offline | Без сети: всё нужное должно уже лежать в ~/.m2 |
-q | --quiet | Только ошибки |
-X | --debug | Отладочный вывод: параметры плагинов, classpath, откуда что скачивается |
-e | --errors | Полный стек исключения при ошибке |
-B | --batch-mode | Неинтерактивный режим для CI и скриптов |
-ntp | --no-transfer-progress | Не печатать прогресс загрузок (с Maven 3.6.1) |
-Dname=value | --define | Пользовательское свойство: перекрывает <properties> POM и параметры плагинов |
-P prod,it | --activate-profiles | Включить профили; -P '!dev' — выключить (Активация профиля) |
-s / -gs | --settings / --global-settings | Другой пользовательский / глобальный settings.xml (например, с зеркалом на CI) |
-T 4, -T 1C | --threads | Параллельная сборка модулей: число потоков или потоков на ядро |
-N | --non-recursive | Не собирать модули из <modules> |
-f path | --file | Использовать указанный POM или каталог |
-fae | --fail-at-end | Не останавливаться на первом упавшем модуле: собрать всё, что не зависит от него, и упасть в конце |
-fn | --fail-never | Никогда не завершать сборку ошибкой (см. заметку ниже) |
-v / -V | --version / --show-version | Показать версию и выйти / показать версию и продолжить сборку (удобно в логах CI) |
Ключи, которые нужны в каждом запуске проекта, кладут в файл .mvn/maven.config в корне проекта (надёжнее всего — по одному аргументу на строку, например -ntp и -Dstyle.color=always). Параметры JVM самого Maven (память, кодировка) задают переменной окружения MAVEN_OPTS, например MAVEN_OPTS="-Xmx2g", или файлом .mvn/jvm.config.
Подводный камень: --fail-never в CI-скрипте
mvn -fn verify завершается BUILD SUCCESS и кодом выхода 0, даже если модули упали на компиляции или тестах: провал виден только в Reactor Summary. В скрипте CI такая сборка считается зелёной. Если нужно увидеть ошибки всех модулей сразу, используйте -fae: сборка дойдёт до конца, но завершится ошибкой.
Частые ошибки Maven и их решение
Почти любая ошибка Maven начинается со строки [ERROR] Failed to execute goal или с ошибки чтения POM до начала сборки. В первой строке уже есть всё главное: какой плагин и какая цель упали, в каком модуле и почему. Подробности дают повторный запуск с -e (стек исключения) и -X (отладочный лог).
Пример (примерный вид для Maven 3.9.x; путь и номер строки зависят от проекта):
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project shop-web: Compilation failure
[ERROR] /home/user/shop/shop-web/src/main/java/com/examclouds/web/App.java:[12,9] cannot find symbol
...
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging. Как читать: maven-compiler-plugin:3.13.0:compile — плагин, его версия и цель; (default-compile) — id выполнения: префикс default- означает стандартную привязку к фазе, default-cli — цель вызвана из командной строки, другое имя — execution из вашего pom.xml; on project shop-web — модуль; после двоеточия — причина. Следующие строки уточняют причину, а для многомодульной сборки в конце есть подсказка -rf :shop-web. Тексты сообщений в таблице ниже сокращены, точная формулировка зависит от версии Maven и плагина.
| Сообщение или симптом | Причина | Решение |
|---|---|---|
«"mvn" не является внутренней или внешней командой» (cmd), mvn: command not found | Каталог bin Maven не в PATH или терминал открыт до изменения переменных | Добавить bin в PATH, открыть новый терминал (ошибки установки) |
The JAVA_HOME environment variable is not defined correctly | JAVA_HOME указывает на bin или на несуществующий путь | JAVA_HOME = корень JDK (ошибки установки) |
... requires a project to execute but there is no POM in this directory | Команда запущена не в каталоге с pom.xml | cd в корень проекта или -f path/pom.xml (первый проект) |
Could not resolve dependencies ... Could not find artifact com.examclouds:shop-core:jar:1.0-SNAPSHOT | Опечатка в координатах; артефакт есть только в чьём-то локальном ~/.m2; не настроен корпоративный репозиторий; соседний модуль собирается из подкаталога | Проверить GAV, настроить репозиторий, собирать модули из корня с -pl ... -am (ошибки репозиториев) |
... was cached in the local repository, resolution will not be reattempted until the update interval ... | Maven запомнил неудачную загрузку | Исправить причину и запустить с -U (Как Maven ищет зависимость) |
501 HTTPS Required; Blocked mirror for repositories: [...] | Адрес репозитория по HTTP: Maven Central с 2020 года только HTTPS, а Maven 3.8.1+ блокирует внешние HTTP-репозитории (maven-default-http-blocker) | Заменить http:// на https:// в pom.xml и settings.xml (актуальные версии) |
Source option 7 is no longer supported. Use 8 or later.; release version 25 not supported | Устаревшие source/target из старого архетипа; JDK, на котором запущен Maven, ниже release | maven.compiler.release вместо source/target; сверить JDK в mvn -v (минимальный pom.xml) |
package org.junit.jupiter.api does not exist при mvn compile | Тест лежит в src/main/java или основной код использует библиотеку со scope = test | Перенести класс в src/test/java или исправить scope (Scope) |
NoSuchMethodError / NoClassDefFoundError при запуске, сборка проходит | Конфликт версий: Maven оставил одну версию библиотеки по правилу nearest wins | dependency:tree -Dverbose, явная версия или exclusions (Конфликт версий) |
no main manifest attribute, in target/...jar | В манифесте jar нет Main-Class | Настроить maven-jar-plugin или запускать через java -cp (Исполняемый jar) |
Non-resolvable parent POM ... | Родитель не найден ни по relativePath, ни в репозиториях | Проверить <relativePath> и GAV родителя или собрать из корня (parent POM) |
The projects in the reactor contain a cyclic reference | Два модуля зависят друг от друга | Вынести общий код в отдельный модуль (Зависимости между модулями) |
No plugin found for prefix '...' | Вместо префикса указан artifactId (maven-checkstyle-plugin:check) или плагин не из стандартных групп | Короткий префикс (checkstyle:check) или полные координаты (Как запустить плагин) |
Тесты не запускаются: Tests run: 0 или блока тестов нет | Имя класса не по шаблону Surefire (*Test и др.); *IT без failsafe; очень старый Surefire (до 2.22.0) не видит JUnit 5 | Переименовать класс, подключить failsafe, обновить Surefire (surefire и failsafe) |
Unknown lifecycle phase ".examclouds" | PowerShell разбил аргумент -DgroupId=com.examclouds | Взять каждый -D... в кавычки (первый проект) |
OutOfMemoryError: Java heap space, медленная сборка | Мало памяти JVM Maven или JVM тестов; лишний clean, проверка обновлений при каждом запуске | MAVEN_OPTS="-Xmx2g" для Maven, argLine для тестов (заметка ниже); -T 1C; clean только при необходимости |
Нюанс: MAVEN_OPTS не помогает тестам
По умолчанию Surefire запускает тесты в отдельной JVM (fork), и MAVEN_OPTS на неё не действует: если OutOfMemoryError падает внутри теста, увеличение -Xmx в MAVEN_OPTS ничего не изменит. Память для JVM тестов задают параметром Surefire argLine: mvn test -DargLine="-Xmx1g" или <argLine> в конфигурации плагина. MAVEN_OPTS нужен, когда память кончается у самого Maven — при компиляции или в большом reactor.
Часто задаваемые вопросы
Какую команду запускать на CI: mvn clean install или mvn clean verify?
Для проверки pull request — mvn -B -ntp clean verify: выполняются все тесты и проверки, а локальный репозиторий агента не засоряется. install нужен, только если следующий шаг собирает другой проект, которому нужен этот артефакт из ~/.m2; для публикации в Nexus или Artifactory — deploy. Подробнее — в разделе Основные команды сборки.
Как пропустить тесты в Maven?
Обычно — -DskipTests: тесты компилируются, но не запускаются. -Dmaven.test.skip=true пропускает и компиляцию тестов, поэтому ошибки в тестовом коде остаются незамеченными. Только интеграционные тесты пропускает -DskipITs. Все варианты — в таблице раздела Тесты.
Как заставить Maven обновить SNAPSHOT-зависимость?
Запустить сборку с ключом -U: Maven проверит обновления SNAPSHOT во всех удалённых репозиториях, не дожидаясь интервала проверки (по умолчанию раз в сутки), и забудет закэшированные неудачные загрузки. Если файлы в ~/.m2 повреждены, помогает mvn dependency:purge-local-repository.
Как узнать версию проекта из командной строки?
Командой mvn help:evaluate -Dexpression=project.version -q -DforceStdout — она печатает только значение, например 1.0-SNAPSHOT, и подходит для скриптов. Версию самого Maven и JDK показывает mvn -v. Пример со скриптом — в разделе Диагностика.
Почему Maven скачивает зависимости при каждой сборке?
Чаще всего локальный репозиторий каждый раз пустой: CI-агент или Docker-контейнер стартует без ~/.m2 (кэшируйте этот каталог) или в команде задан -Dmaven.repo.local на временный путь. Если в логе только maven-metadata.xml, Maven проверяет обновления SNAPSHOT — так бывает при -U в каждом запуске. Без сети работает -o, если всё нужное уже скачано.
Практика по теме
Закрепите урок на задачах — у каждой есть уровень и оценка времени.
- Фазы и цели: что на самом деле выполняет mvn package
- Конфликт версий Guava: воспроизвести NoSuchMethodError и исправить
Комментарии