1. Введение

1.1. Основные понятия

Apache Maven – это инструмент для управления зависимостями и сборки проектов. Он позволяет разработчикам полностью управлять lifecycle (жизненным циклом) проекта. Благодаря этому, команда может автоматизировать процессы, связанные со сборкой, тестированием, упаковкой проекта и т.д.

В случае, когда над проектом работает несколько команд разработчиков, Apache Maven позволяет работать в соответствии с определенными стандартами.

Основные аспекты, которыми позволяет управлять Apache Maven:

  • Создание

  • Документирование

  • Отчёты

  • Зависимости

  • Релизы

  • SCM

  • Список рассылки

  • Дистрибьюция

1.2. Основная цель

Основной целью Apache Maven является предоставление разработчику:

  • Понятной модели для проектов, которая может быть использована повторно и была бы проста в поддержании.

  • Плагины, которые могут взаимодействовать с этой моделью.

Структура и содержание проекта Apache Maven указывается в специальном xml-файле, который называется Project Object Model (POM). Этот файл является базовым модулем всей системы.

1.3. Соглашение по конфигурации

Разработчики не обязаны указывать каждую деталь. Apache Maven обеспечивает поведение проекта по умолчанию. Когда создается проект с использованием этой технологии, то Apache Maven создаёт базовую структуру проекта. Разработчики несут ответственность только за соответственное размещение файлов.

Table 1. Значения по умолчанию для исходного кода проекта и других модулей.
Назначение Имя директории

Исходный код

./src/main/java

Ресурсы

./src/main/resources

Тесты

./src/test

Дистрибутив JAR

./target

Скомпилированный байт-код

./target/classes

Для того чтобы построить проект, Apache Maven предоставляет настройки для управления lifecycle проекта и его dependencies (зависимостями). Огромное количество задач поддерживается с помощью различных plugins (плагинов).

Можно создавать проекты с использованием Apache Maven без понимания того, как работают эти отдельные plugins.

2. POM

POM (Project Object Model) является базовым модулем Apache Maven. Это специальный XML-файл, который всегда хранится в базовой директории проекта и называется pom.xml.

Файл POM содержит информацию о проекте и различных деталях конфигурации, которые используются Apache Maven для создания проекта.

Этот файл также содержит goals (задачи) и plugins. Во время выполнения задач, Apache Maven ищет файл pom.xml в базовой директории проекта. Он читает его и получает необходимую информацию, после чего выполняет goals.

Среди конфигураций Apache Maven можно выделить следующие:

  • dependencies (зависимости) проекта

  • plugins (плагины)

  • goals (задачи)

  • profile (профиль создания)

  • version (версия) проекта

  • developer (разработчики)

  • список рассылки

pom
Общая структура POM

Перед тем, как создавать pom.xml необходимо прежде всего определить группу проекта (groupId), его имя (artifactId) и его версию (version). Все это поможет унифицировать проект для более простой его идентификации в repository (репозитории).

Пример pom.xml файла:
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.companyname.project-group</groupId>
    <artifactId>project</artifactId>
    <version>1.0</version>
</project>

Каждый проект должен иметь свой собственный POM файл.

Все POM файлы должны иметь три обязательных элемента:

  • groupId

  • artifactId

  • version

В репозитории проект выглядит следующим образом: groupId:artifactId:version.

Ключевой элемент в POM файле – это project, который делится на три главных подгруппы:

  • groupId
    Это ID группы проекта. Зачастую, это уникальная организация или проект. Например, если нужно создать группу, которая разрабатывает проекты отвечающие за видео в компании, владеющей доменным именем rakovets.by, то groupId будет выглядеть, примерно так: by.rakovets.video. В этой группе будут все проекты данной компании, которые относятся к видео.

  • artifactId
    Это идентификатор самого проекта. Чаще всего – его имя. Например: video-converter. artifactId также помогает найти проект в репозитории.

  • version
    Версия проекта. Определяет конкретную версию продукта. Например: by.rakovets.video:video-converter:1.0, by.rakovets.video:video-converter:1.1

2.1. Супер POM

Все POM-файлы являются наследниками parent POM (родительского POM). Этот POM-файл называется Super POM и содержит значения, унаследованные по умолчанию.

Простой способ просмотреть настройки по умолчанию Super POM файла – это использование команды:

mvn help:effective-pom

2.1.1. Пример

Для понимания того, как это работает на практике, рассмотрим простой пример.

Создадим простой maven-проект:

mvn archetype:generate
...
1608: remote -> net.sf.jlue:jlue-archetype-basic (Archetype - basic project for Jlue)
1609: remote -> net.sf.jlue:jlue-archetype-blank (Archetype - blank project for Jlue)
1610: remote -> net.sf.maven-autotools:maven-autotools-archetype-executable (-)
1611: remote -> net.sf.maven-autotools:maven-autotools-archetype-shared (-)
1612: remote -> net.sf.maven-har:maven-archetype-har (-)
1613: remote -> net.sf.maven-sar:maven-archetype-sar (-)
1614: remote -> net.sf.mgp:maven-archetype-gwt (An archetype which contains a sample Maven GWT project.)
...

В полученном списке ищем net.sf.maven-har:maven-archetype-har и его позицию в этос списке (целое число, на момент выполнения это 1612).

Далее последовательно отвечаем на запросы в CLI:

  • Choose a number: 2: нажимаем Enter (по умолчанию)

  • Define value for property 'groupId': пишем by.rakovets.example

  • Define value for property 'artifactId': пишем example-maven

  • Define value for property 'version' 1.0-SNAPSHOT: : нажимаем Enter (по умолчанию)

  • Define value for property 'package' by.rakovets.example: : нажимаем Enter (подтверждение)

  • ` Y: :` нажимаем Enter (подтверждение)

Это выглядит следующим образом:

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1793: 1612
Choose net.sf.maven-har:maven-archetype-har version:
1: 0.9
2: 1.0
Choose a number: 2:
Define value for property 'groupId': by.rakovets.example
Define value for property 'artifactId': example-maven
Define value for property 'version' 1.0-SNAPSHOT: :
Define value for property 'package' by.rakovets.example: :
Confirm properties configuration:
groupId: by.rakovets.example
artifactId: example-maven
version: 1.0-SNAPSHOT
package: by.rakovets.example
 Y: :

После последнего подтверждения получится:

[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-har:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: basedir, Value: /home/rakovets/example
[INFO] Parameter: package, Value: by.rakovets.example
[INFO] Parameter: groupId, Value: by.rakovets.example
[INFO] Parameter: artifactId, Value: example-maven
[INFO] Parameter: packageName, Value: by.rakovets.example
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /home/rakovets/example/example-maven
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  02:15 min
[INFO] Finished at: 2021-06-09T06:04:33+03:00
[INFO] ------------------------------------------------------------------------

Созданный проект будет иметь следующую структуру:

example-maven
├── pom.xml
└── src
    └── main
        ├── java
        │   └── by
        │       └── rakovets
        │           └── example
        │               └── FoobarPojo.java
        └── resources
            ├── FoobarPojo.hbm.xml
            └── META-INF
                └── jboss-service.xml
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>by.rakovets.example</groupId>
    <artifactId>example-maven</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>har</packaging>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>net.sf.maven-har</groupId>
                <artifactId>maven-har-plugin</artifactId>
                <version>0.9</version>
                <extensions>true</extensions>
            </plugin>
        </plugins>
    </build>
</project>

Переходим в директорию с проектом и выполняем команду:

mvn help:effective-pom

В результате получим, примерно, следующий результат:

[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:example-maven >------------------
[INFO] Building example-maven 1.0-SNAPSHOT
[INFO] --------------------------------[ har ]---------------------------------
[INFO]
[INFO] --- maven-help-plugin:3.2.0:effective-pom (default-cli) @ example-maven ---
[INFO]
Effective POMs, after inheritance, interpolation, and profiles are applied:

<?xml version="1.0" encoding="UTF-8"?>
<!-- ====================================================================== -->
<!--                                                                        -->
<!-- Generated by Maven Help Plugin on 2021-06-09T06:11:05+03:00            -->
<!-- See: http://maven.apache.org/plugins/maven-help-plugin/                -->
<!--                                                                        -->
<!-- ====================================================================== -->
<!-- ====================================================================== -->
<!--                                                                        -->
<!-- Effective POM for project                                              -->
<!-- 'by.rakovets.example:example-maven:har:1.0-SNAPSHOT'                   -->
<!--                                                                        -->
<!-- ====================================================================== -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>by.rakovets.example</groupId>
  <artifactId>example-maven</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>har</packaging>
  <repositories>
    <repository>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <releases>
        <updatePolicy>never</updatePolicy>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
    </pluginRepository>
  </pluginRepositories>
  <build>
    <sourceDirectory>/home/rakovets/example/example-maven/src/main/java</sourceDirectory>
    <scriptSourceDirectory>/home/rakovets/example/example-maven/src/main/scripts</scriptSourceDirectory>
    <testSourceDirectory>/home/rakovets/example/example-maven/src/test/java</testSourceDirectory>
    <outputDirectory>/home/rakovets/example/example-maven/target/classes</outputDirectory>
    <testOutputDirectory>/home/rakovets/example/example-maven/target/test-classes</testOutputDirectory>
    <resources>
      <resource>
        <directory>/home/rakovets/example/example-maven/src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>/home/rakovets/example/example-maven/src/test/resources</directory>
      </testResource>
    </testResources>
    <directory>/home/rakovets/example/example-maven/target</directory>
    <finalName>example-maven-1.0-SNAPSHOT</finalName>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.3</version>
        </plugin>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-5</version>
        </plugin>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.8</version>
        </plugin>
        <plugin>
          <artifactId>maven-release-plugin</artifactId>
          <version>2.5.3</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <executions>
          <execution>
            <id>default-compile</id>
            <phase>compile</phase>
            <goals>
              <goal>compile</goal>
            </goals>
            <configuration>
              <source>1.5</source>
              <target>1.5</target>
            </configuration>
          </execution>
          <execution>
            <id>default-testCompile</id>
            <phase>test-compile</phase>
            <goals>
              <goal>testCompile</goal>
            </goals>
            <configuration>
              <source>1.5</source>
              <target>1.5</target>
            </configuration>
          </execution>
        </executions>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>net.sf.maven-har</groupId>
        <artifactId>maven-har-plugin</artifactId>
        <version>0.9</version>
        <extensions>true</extensions>
        <executions>
          <execution>
            <id>default-har</id>
            <phase>package</phase>
            <goals>
              <goal>har</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>2.5</version>
        <executions>
          <execution>
            <id>default-clean</id>
            <phase>clean</phase>
            <goals>
              <goal>clean</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>3.2.0</version>
        <executions>
          <execution>
            <id>default-testResources</id>
            <phase>process-test-resources</phase>
            <goals>
              <goal>testResources</goal>
            </goals>
          </execution>
          <execution>
            <id>default-resources</id>
            <phase>process-resources</phase>
            <goals>
              <goal>resources</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.0.0-M5</version>
        <executions>
          <execution>
            <id>default-test</id>
            <phase>test</phase>
            <goals>
              <goal>test</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-install-plugin</artifactId>
        <version>3.0.0-M1</version>
        <executions>
          <execution>
            <id>default-install</id>
            <phase>install</phase>
            <goals>
              <goal>install</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-deploy-plugin</artifactId>
        <version>3.0.0-M1</version>
        <executions>
          <execution>
            <id>default-deploy</id>
            <phase>deploy</phase>
            <goals>
              <goal>deploy</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-site-plugin</artifactId>
        <version>3.3</version>
        <executions>
          <execution>
            <id>default-site</id>
            <phase>site</phase>
            <goals>
              <goal>site</goal>
            </goals>
            <configuration>
              <outputDirectory>/home/rakovets/example/example-maven/target/site</outputDirectory>
              <reportPlugins>
                <reportPlugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-project-info-reports-plugin</artifactId>
                </reportPlugin>
              </reportPlugins>
            </configuration>
          </execution>
          <execution>
            <id>default-deploy</id>
            <phase>site-deploy</phase>
            <goals>
              <goal>deploy</goal>
            </goals>
            <configuration>
              <outputDirectory>/home/rakovets/example/example-maven/target/site</outputDirectory>
              <reportPlugins>
                <reportPlugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-project-info-reports-plugin</artifactId>
                </reportPlugin>
              </reportPlugins>
            </configuration>
          </execution>
        </executions>
        <configuration>
          <outputDirectory>/home/rakovets/example/example-maven/target/site</outputDirectory>
          <reportPlugins>
            <reportPlugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-project-info-reports-plugin</artifactId>
            </reportPlugin>
          </reportPlugins>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <reporting>
    <outputDirectory>/home/rakovets/example/example-maven/target/site</outputDirectory>
  </reporting>
</project>


[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  9.075 s
[INFO] Finished at: 2021-06-09T06:11:05+03:00
[INFO] ------------------------------------------------------------------------

Представим в виде xml-файла:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>by.rakovets.example</groupId>
    <artifactId>example-maven</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>har</packaging>
    <repositories>
        <repository>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>central</id>
            <name>Central Repository</name>
            <url>https://repo.maven.apache.org/maven2</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <releases>
                <updatePolicy>never</updatePolicy>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>central</id>
            <name>Central Repository</name>
            <url>https://repo.maven.apache.org/maven2</url>
        </pluginRepository>
    </pluginRepositories>
    <build>
        <sourceDirectory>/home/rakovets/example/example-maven/src/main/java</sourceDirectory>
        <scriptSourceDirectory>/home/rakovets/example/example-maven/src/main/scripts</scriptSourceDirectory>
        <testSourceDirectory>/home/rakovets/example/example-maven/src/test/java</testSourceDirectory>
        <outputDirectory>/home/rakovets/example/example-maven/target/classes</outputDirectory>
        <testOutputDirectory>/home/rakovets/example/example-maven/target/test-classes</testOutputDirectory>
        <resources>
            <resource>
                <directory>/home/rakovets/example/example-maven/src/main/resources</directory>
            </resource>
        </resources>
        <testResources>
            <testResource>
                <directory>/home/rakovets/example/example-maven/src/test/resources</directory>
            </testResource>
        </testResources>
        <directory>/home/rakovets/example/example-maven/target</directory>
        <finalName>example-maven-1.0-SNAPSHOT</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-antrun-plugin</artifactId>
                    <version>1.3</version>
                </plugin>
                <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>2.2-beta-5</version>
                </plugin>
                <plugin>
                    <artifactId>maven-dependency-plugin</artifactId>
                    <version>2.8</version>
                </plugin>
                <plugin>
                    <artifactId>maven-release-plugin</artifactId>
                    <version>2.5.3</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <executions>
                    <execution>
                        <id>default-compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <configuration>
                            <source>1.5</source>
                            <target>1.5</target>
                        </configuration>
                    </execution>
                    <execution>
                        <id>default-testCompile</id>
                        <phase>test-compile</phase>
                        <goals>
                            <goal>testCompile</goal>
                        </goals>
                        <configuration>
                            <source>1.5</source>
                            <target>1.5</target>
                        </configuration>
                    </execution>
                </executions>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>net.sf.maven-har</groupId>
                <artifactId>maven-har-plugin</artifactId>
                <version>0.9</version>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <id>default-har</id>
                        <phase>package</phase>
                        <goals>
                            <goal>har</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <version>2.5</version>
                <executions>
                    <execution>
                        <id>default-clean</id>
                        <phase>clean</phase>
                        <goals>
                            <goal>clean</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.2.0</version>
                <executions>
                    <execution>
                        <id>default-testResources</id>
                        <phase>process-test-resources</phase>
                        <goals>
                            <goal>testResources</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>default-resources</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>resources</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
                <executions>
                    <execution>
                        <id>default-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-install-plugin</artifactId>
                <version>3.0.0-M1</version>
                <executions>
                    <execution>
                        <id>default-install</id>
                        <phase>install</phase>
                        <goals>
                            <goal>install</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>3.0.0-M1</version>
                <executions>
                    <execution>
                        <id>default-deploy</id>
                        <phase>deploy</phase>
                        <goals>
                            <goal>deploy</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.3</version>
                <executions>
                    <execution>
                        <id>default-site</id>
                        <phase>site</phase>
                        <goals>
                            <goal>site</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>/home/rakovets/example/example-maven/target/site</outputDirectory>
                            <reportPlugins>
                                <reportPlugin>
                                    <groupId>org.apache.maven.plugins</groupId>
                                    <artifactId>maven-project-info-reports-plugin</artifactId>
                                </reportPlugin>
                            </reportPlugins>
                        </configuration>
                    </execution>
                    <execution>
                        <id>default-deploy</id>
                        <phase>site-deploy</phase>
                        <goals>
                            <goal>deploy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>/home/rakovets/example/example-maven/target/site</outputDirectory>
                            <reportPlugins>
                                <reportPlugin>
                                    <groupId>org.apache.maven.plugins</groupId>
                                    <artifactId>maven-project-info-reports-plugin</artifactId>
                                </reportPlugin>
                            </reportPlugins>
                        </configuration>
                    </execution>
                </executions>
                <configuration>
                    <outputDirectory>/home/rakovets/example/example-maven/target/site</outputDirectory>
                    <reportPlugins>
                        <reportPlugin>
                            <groupId>org.apache.maven.plugins</groupId>
                            <artifactId>maven-project-info-reports-plugin</artifactId>
                        </reportPlugin>
                    </reportPlugins>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <reporting>
        <outputDirectory>/home/rakovets/example/example-maven/target/site</outputDirectory>
    </reporting>
</project>

В полученном файле можно видеть изначальную структуру проекта, директорию вывода, необходимые плагины, репозитории, которые Apache Maven будет использовать во время выполнения необходимых задач.

Apache Maven также обеспечивает множество archetype (архитипов) для создания проектов, имеющих определённую структуру и конфигурацию файла pom.xml.

3. Plugins

Apache Maven – это инструмент, одной из задач которого является сборка проекта. Сборка проекта достигается с помощью plugins. Любая goals, по сути своей, выполняется с помощью plugins.

Apache Maven Plugins используются для:

  • создания jar – файла

  • создания war – файла

  • компиляции кода файлов

  • юнит-тестирования кода

  • создание отчётов проекта

  • создание документации проекта

В общей форме, plugin обеспечивает набор goals, которые могут быть выполнены с помощью такого синтаксиса:

mvn [имя-плагина]:[имя-цели]

Например, для того, чтобы выполнить компиляцию проекта, необходимо использовать следующую команду:

mvn compiler:compile

3.1. Типы плагинов

Существует два типа плагинов в Apache Maven:

  • Плагины сборки
    Выполняются в процессе сборки и должны быть конфигурированы внутри блока <build></build> файла pom.xml

  • Плагины отчётов
    Выполняются в процесса генерирования сайта и должны быть конфигурированы внутри блока <reporting></reporting> файла pom.xml.

Вот список, наиболее используемых плагинов:

clean Очищает цель после сборки. Удаляет директорию target.

compiler

Компилирует исходные Java файлы.

surefire

Запускает тесты JUnit. Создаёт отчёты о тестировании.

jar

Собирает JAR файл текущего проекта.

war

Собирает WAR файл текущего проекта.

javadoc

Генерирует Javadoc проекта.

antrun

Запускает набор задач ant из любой указанной фазы.

Подробнее: Maven Plugins

Для понимания того, как это работает на практике, рассмотрим следующий пример:

<?xml version="1.0" encoding="UTF-8"?>
<project
        xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example</groupId>
    <artifactId>maven-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.1</version>
                <executions>
                    <execution>
                        <id>id.clean</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>compile phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

После этого выполним в терминале следующую команду:

mvn compile

В результате выполнения команды, получим, примерно, следующий результат:

[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:maven-example >------------------
[INFO] Building maven-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory   /home/rakovetsmaven/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-example ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (id.clean) @ maven-example ---
[INFO] Executing tasks
     [echo] compile phase
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.389 s
[INFO] Finished at: 2021-10-15T05:57:24+03:00
[INFO] ------------------------------------------------------------------------

Пример, приведённый выше, демонстрирует следующие ключевые концепции:

  • Plugins указываются в файле pom.xml внутри блока <plugins></plugins>.

  • Каждый plugin может иметь несколько goals.

  • Можно определять phase, из которой можно начать выполнение plugin. В примере выше использовалась phase compile.

3.2. maven-jar-plugin

3.3. Configure runnable JAR

<plugin>
    <!-- Build an executable JAR -->
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.2.0</version>
    <configuration>
        <archive>
            <manifest>
                <mainClass>
                    by.rakovets.maven.App
                </mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

4. Жизненный цикл сборки

Жизненный цикл сборки (lifecycle) в Apache Maven – это чётко определённая последовательность phases (фаз) во время выполнения которых должны быть достигнуты определённые цели.

Типичный жизненный цикл сборки Apache Maven выглядит следующим образом:

Фаза Действия Описание

prepare-resources

копирование ресурсов

В этой фазе происходит копирование ресурсов, которое, также, может быть настроено.

compile

компиляция

В этой фазе происходит компиляция исходного кода.

package

упаковка проекта

В этой фазе, в зависимости от настроек создаётся архив JAR/WAR. Тип архива указывается в pom.xml файле.

install

установка

В этой фазе происходит установка пакета в локальный/удалённый репозиторий Apache Maven.

Каждая из этих phase (фаз) имеет phases pre и post. Они могут быть использованы для регистрации goals (задач), которые должны быть запущены перед и после указанной phase.

flow

Когда Apache Maven начинает сборку проекта, он проходит через определённую последовательность phases и выполняет определённые goals, которые указаны в каждой из фаз.

phases
Lifecycle Phases

Apache Maven имеет следующие 3 стандартных lifecycles:

  • clean

  • default

  • site

Goal (задача) – это специальная задача, которая относится к сборке проекта и его управлению. Она может привязываться как к нескольким фазам, так и ни к одной. Goal, которая не привязана ни к одной фазе, может быть запущена вне фаз сборки с помощью прямого вызова.

Порядок выполнения зависит от порядка вызова goals и phases.

Например, рассмотрим следующую команду:

mvn clean dependency:copy-dependencies package

Аргументы clean и package являются phases сборки, а dependency:copy-dependencies является goal.

В этом случае сначала будет выполнена phase clean, после этого будет выполнена goal dependency:copy-dependencies. После чего будет выполнена фаза package.

4.1. Жизненный цикл clean

Рассмотрим команду:

mvn clean

Goal clean Apache Maven (clean:clean) привязывается к phase clean в жизненном цикле сборки. Эта задача удаляет ввод сборки путём удаления директории сборки (обычно ./target). Таким образом, когда выполняется команда mvn clean, Apache Maven удаляет директорию сборки.

Можно настроить различное поведение привязав goals к любой из phases сборки.

Рассмотрим пример, в котором привяжем goal maven-antrun-plugin:run к фазам pre-clean, clean и post-clean.

Пример:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>by.rakovets.example</groupId>
    <artifactId>example-maven</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.1</version>
                <executions>
                    <execution>
                        <id>id.pre-clean</id>
                        <phase>pre-clean</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>pre-clean phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <id>id.clean</id>
                        <phase>clean</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>clean phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <id>id.post-clean</id>
                        <phase>post-clean</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>post-clean phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

После этого выполним в CLI следующую команду:

mvn clean

В результате получим следующий результат:

[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:example-maven >------------------
[INFO] Building example-maven 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (id.pre-clean) @ example-maven ---
[INFO] Executing tasks
     [echo] pre-clean phase
[INFO] Executed tasks
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ example-maven ---
[INFO] Deleting /home/rakovets/example/example-maven/target
[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (id.clean) @ example-maven ---
[INFO] Executing tasks
     [echo] clean phase
[INFO] Executed tasks
[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (id.post-clean) @ example-maven ---
[INFO] Executing tasks
     [echo] post-clean phase
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.270 s
[INFO] Finished at: 2021-06-09T06:34:43+03:00
[INFO] ------------------------------------------------------------------------

Можем выполнить такие же действия для фаз pre-clean и pre-clean.

4.2. Жизненный цикл default

default - это основной жизненный цикл Apache Maven, который используется для сборки проектов. Он включает в себя 23 phases:

Фаза жизненного цикла Описание

validate

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

*initialize`

Инициализирует состояние сборки, например, различные настройки.

generate-sources

Включает любой исходный код в фазу компиляции.

process-sources

Обрабатывает исходный код (т.е. подготавливает). Например, фильтрует определённые значения.

generate-resources

Генерирует ресурсы, которые должны быть включены в пакет.

process-resources

Копирует и отправляет ресурсы в указанную директорию. Это фаза перед упаковкой.

compile

Компилирует исходный код проекта.

process-classes

Обработка файлов, полученных в результате компиляции. Например, оптимизация байт-кода Java классов.

generate-test-sources

Генерирует любые тестовые ресурсы, которые должны быть включены в фазу компиляции.

process-test-sources

Обрабатывает исходный код тестов. Например, фильтрует значения.

test-compile

Компилирует исходный код тестов в указанную директорию тестов.

process-test-classes

Обрабатывает файлы, полученные в результате компиляции исходного кода тестов.

test

Запускает тесты, используя приемлемый фреймворк unit-тестирования (например, JUnit).

prepare-package

Выполняет все необходимые операции для подготовки пакет, непосредственно перед упаковкой.

package

Преобразует скомпилированный код и пакет в дистрибутивный формат. Такие, как JAR, WAR или EAR.

pre-integration-test

Выполняет необходимые действия перед выполнением интеграционных тестов.

integration-test

Обрабатывает и распаковывает пакет, если необходимо, в среду, где будут выполняться интеграционные тесты.

post-integration-test

Выполняет действия, необходимые после выполнения интеграционных тестов. Например, освобождение ресурсов.

verify

Выполняет любые проверки для подтверждения того, что пакет пригоден и отвечает критериям качества.

install

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

deploy

Копирует финальный пакет (архив) в удалённый репозиторий для, того, чтобы сделать его доступным другим разработчикам и проектам.

Необходимо уточнить два момента:

  • Когда выполняем maven-команду, например install, то будут выполнены phases до install и фаза install.

  • Различные goals будут привязаны к различным phases жизненного цикла в зависимости от типа архива (JAR/WAR/EAR).

lifecycle

В следующем примере, привязываем goal maven-antrun-plugin:run к нескольким phases жизненного цикла сборки. Это также позволяет вызывать текстовые сообщения, отображая phase жизненного цикла.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>by.rakovets.example</groupId>
    <artifactId>example-maven</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.1</version>
                <executions>
                    <execution>
                        <id>id.validate</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>validate phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <id>id.compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>compile phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <id>id.test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>test phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <id>id.package</id>
                        <phase>package</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>package phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <id>id.deploy</id>
                        <phase>deploy</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>deploy phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

После этого выполним следующую команду:

mvn compile

В результате получим, примерно, следующий результат:

[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:example-maven >------------------
[INFO] Building example-maven 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (id.validate) @ example-maven ---
[INFO] Executing tasks
     [echo] validate phase
[INFO] Executed tasks
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ example-maven ---
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ example-maven ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (id.compile) @ example-maven ---
[INFO] Executing tasks
     [echo] compile phase
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.484 s
[INFO] Finished at: 2021-06-09T06:42:41+03:00
[INFO] ------------------------------------------------------------------------

4.3. Жизненный цикл site

Жизненный цикл site – используется для создания докладов, документации, развёртывания и т.д.

Он включает в себя такие phases:

  • pre-site

  • site

  • post-site

  • site-deploy

В примере ниже прикрепляем задачу maven-antrun-plugin:run ко всем фазам жизненного цикла site. Это позволяет вызывать текстовые сообщения для отображения фаз жизненного цикла.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>by.rakovets.example</groupId>
    <artifactId>example-maven</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-site-plugin</artifactId>
                <version>3.9.1</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.8</version>
                <executions>
                    <execution>
                        <id>id.pre-site</id>
                        <phase>pre-site</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>pre-site phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <id>id.site</id>
                        <phase>site</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>site phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <id>id.post-site</id>
                        <phase>post-site</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>post-site phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                    <execution>
                        <id>id.site-deploy</id>
                        <phase>site-deploy</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <echo>site-deploy phase</echo>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Теперь выполним команду:

mvn site

В результате получим, примерно, следующий результат:

[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:example-maven >------------------
[INFO] Building example-maven 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-antrun-plugin:1.8:run (id.pre-site) @ example-maven ---
[INFO] Executing tasks

main:
     [echo] pre-site phase
[INFO] Executed tasks
[INFO]
[INFO] --- maven-site-plugin:3.9.1:site (default-site) @ example-maven ---
[INFO] configuring report plugin org.apache.maven.plugins:maven-project-info-reports-plugin:3.1.2
[INFO] 15 reports detected for maven-project-info-reports-plugin:3.1.2: ci-management, dependencies, dependency-info, dependency-management, distribution-management, index, issue-management, licenses, mailing-lists, modules, plugin-management, plugins, scm, summary, team
[INFO] Rendering site with default locale English (en)
[INFO] Rendering content with org.apache.maven.skins:maven-default-skin:jar:1.3 skin.
[INFO] Generating "Dependency Information" report --- maven-project-info-reports-plugin:3.1.2:dependency-info
[INFO] Generating "About" report         --- maven-project-info-reports-plugin:3.1.2:index
[INFO] Generating "Plugin Management" report --- maven-project-info-reports-plugin:3.1.2:plugin-management
[INFO] Generating "Plugins" report       --- maven-project-info-reports-plugin:3.1.2:plugins
[INFO] Generating "Summary" report       --- maven-project-info-reports-plugin:3.1.2:summary
[INFO]
[INFO] --- maven-antrun-plugin:1.8:run (id.site) @ example-maven ---
[INFO] Executing tasks

main:
     [echo] site phase
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.694 s
[INFO] Finished at: 2021-06-09T06:50:32+03:00
[INFO] ------------------------------------------------------------------------

4.4. Полная схема lifecycles

lifecycle full

5. Создание проекта

Создать maven-project можно 3 способами:

  • С помощью Apache Maven и его plugin archetype.

  • С помощью какого-то стороннего инструмента (например: IDE).

  • Вручную.

При создании вручную необходимо создать структуру проекта и сконфигурировать pom.xml самостоятельно. Поэтому этот способ является не самым удобным.

5.1. Archetype

Maven предоставляет пользователям очень большой список различных типов шаблонов для проектов (2993 шаблонов на 15.10.2021) с использованием концепции Archetype. Maven помогает пользователям быстро создать новый Java-проект с помощью следующей команды.

mvn archetype:generate

Archetype (архитип) – это maven-plugin, задача которого состоит в создании структуры проекта по определённому шаблону.

5.1.1. Создание приложения

Рассмотрим archetype quickstart и создадим с его помощью java-приложение.

Переходим в директорию где нужно создать проект и выполняем следующую команду:

mvn archetype:generate

Эта команда запустит создание java-проекта в интерактивном режиме по шаблону.

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:3.2.0:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:3.2.0:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO]
[INFO] --- maven-archetype-plugin:3.2.0:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: remote -> am.ik.archetype:elm-spring-boot-blank-archetype (Blank multi project for Spring Boot + Elm)
2: remote -> am.ik.archetype:graalvm-blank-archetype (Blank project for GraalVM)
3: remote -> am.ik.archetype:graalvm-springmvc-blank-archetype (Blank project for GraalVM + Spring MVC)

...

1826: remote -> org.apache.maven.archetypes:maven-archetype-portlet (An archetype which contains a sample JSR-268 Portlet.)
1827: remote -> org.apache.maven.archetypes:maven-archetype-profiles (-)
1828: remote -> org.apache.maven.archetypes:maven-archetype-quickstart (An archetype which contains a sample Maven project.)
1829: remote -> org.apache.maven.archetypes:maven-archetype-simple (An archetype which contains a simple Maven project.)
1830: remote -> org.apache.maven.archetypes:maven-archetype-site (An archetype which contains a sample Maven site which demonstrates some of the supported document types like
    APT, XDoc, and FML and demonstrates how to i18n your site. This archetype can be layered
    upon an existing Maven project.)
1831: remote -> org.apache.maven.archetypes:maven-archetype-site-simple (An archetype which contains a sample Maven site.)
1832: remote -> org.apache.maven.archetypes:maven-archetype-site-skin (An archetype which contains a sample Maven Site Skin.)
1833: remote -> org.apache.maven.archetypes:maven-archetype-webapp (An archetype which contains a sample Maven Webapp project.)

...

2988: remote -> ws.osiris:osiris-archetype (Maven Archetype for Osiris)
2989: remote -> xyz.luan.generator:xyz-gae-generator (-)
2990: remote -> xyz.luan.generator:xyz-generator (-)
2991: remote -> za.co.absa.hyperdrive:component-archetype (-)
2992: remote -> za.co.absa.hyperdrive:component-archetype_2.11 (-)
2993: remote -> za.co.absa.hyperdrive:component-archetype_2.12 (-)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1828:

В полученном списке ищем org.apache.maven.archetypes:maven-archetype-quickstart и его позицию в этос списке. Это целое число и на момент выполнения это 1828. Этот archetype используется по умолчанию.

Далее в интерактивном режиме отвечаем на запросы в CLI:

  • Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1828: нажимаем Enter (по умолчанию)

  • Choose org.apache.maven.archetypes:maven-archetype-quickstart version: нажимаем Enter (по умолчанию)

  • Define value for property 'groupId': пишем by.rakovets.example

  • Define value for property 'artifactId': пишем example-maven

  • Define value for property 'version' 1.0-SNAPSHOT: : нажимаем Enter (по умолчанию)

  • Define value for property 'package' by.rakovets.example: : нажимаем Enter (подтверждение)

  • ` Y: :` нажимаем Enter (подтверждение)

Это выглядит следующим образом:

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1828:
Choose org.apache.maven.archetypes:maven-archetype-quickstart version:
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
6: 1.1
7: 1.3
8: 1.4
Choose a number: 8:
Define value for property 'groupId': by.rakovets.example
Define value for property 'artifactId': example-maven
Define value for property 'version' 1.0-SNAPSHOT: :
Define value for property 'package' by.rakovets.example: :
Confirm properties configuration:
groupId: by.rakovets.example
artifactId: example-maven
version: 1.0-SNAPSHOT
package: by.rakovets.example
 Y: : Y
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.4
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: by.rakovets.example
[INFO] Parameter: artifactId, Value: example-maven
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: by.rakovets.example
[INFO] Parameter: packageInPathFormat, Value: by/rakovets/example
[INFO] Parameter: package, Value: by.rakovets.example
[INFO] Parameter: groupId, Value: by.rakovets.example
[INFO] Parameter: artifactId, Value: example-maven
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Project created from Archetype in dir:   /home/rakovetsmaven/example-maven
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  10:46 min
[INFO] Finished at: 2021-10-15T06:36:04+03:00
[INFO] ------------------------------------------------------------------------

Созданный проект будет иметь следующую структуру:

example-maven/
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── by
    │           └── rakovets
    │               └── example
    │                   └── App.java
    └── test
        └── java
            └── by
                └── rakovets
                    └── example
                        └── AppTest.java
pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example</groupId>
    <artifactId>example-maven</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>example-maven</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.7.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-project-info-reports-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
Class App.java
package by.rakovets.example;

/**
 * Hello world!
 *
 */
public class App
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
    }
}
Class AppTest.java
package by.rakovets.example;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

/**
 * Unit test for simple App.
 */
public class AppTest
{
    /**
     * Rigorous Test :-)
     */
    @Test
    public void shouldAnswerWithTrue()
    {
        assertTrue( true );
    }
}

5.2. Создание проекта без интерактивного режима

Если известно название шаблона, то можно ускорить процесс создания, не используя интерактивный режим. Для этого можно использовать команду:

mvn archetype:generate \
    -DgroupId=by.rakovets.example \
    -DartifactId=maven-example \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DarchetypeVersion=1.4 \
    -DinteractiveMode=false
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:3.2.0:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:3.2.0:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO]
[INFO] --- maven-archetype-plugin:3.2.0:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-quickstart:1.4
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: by.rakovets.example
[INFO] Parameter: artifactId, Value: maven-example
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: by.rakovets.example
[INFO] Parameter: packageInPathFormat, Value: by/rakovets/example
[INFO] Parameter: package, Value: by.rakovets.example
[INFO] Parameter: groupId, Value: by.rakovets.example
[INFO] Parameter: artifactId, Value: maven-example
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Project created from Archetype in dir: /home/rakvoets/maven/maven-example
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.639 s
[INFO] Finished at: 2021-10-15T06:48:27+03:00
[INFO] ------------------------------------------------------------------------

В итоге будет создан аналогичный проект.

6. Сборка проекта

Рассмотрим, как протестировать и собрать приложение с помощью Apache Maven. В качестве проекта будет использоваться проект сгенерированный с помощью archetype maven-archetype-quickstart.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example</groupId>
    <artifactId>maven-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>maven-example</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-jar-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                <plugin>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.7.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-project-info-reports-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

В директории проекта необходимо запустить следующую команду:

mvn clean package

В результате получим следующий результат:

Output
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:maven-example >------------------
[INFO] Building maven-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ maven-example ---
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven/maven-example/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ maven-example ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/rakovets/maven/maven-example/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven/maven-example/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ maven-example ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/rakovets/maven/maven-example/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ maven-example ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running by.rakovets.example.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.019 s - in by.rakovets.example.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ maven-example ---
[INFO] Building jar: /home/rakovets/maven/maven-example/target/maven-example-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.542 s
[INFO] Finished at: 2021-10-15T07:02:44+03:00
[INFO] ------------------------------------------------------------------------

Приложение протестировано и собрано.

Структура для директории ./target проекта
target/
├── classes
│   └── by
│       └── rakovets
│           └── example
│               └── App.class
├── generated-sources
│   └── annotations
├── generated-test-sources
│   └── test-annotations
├── maven-archiver
│   └── pom.properties
├── maven-example-1.0-SNAPSHOT.jar
├── maven-status
│   └── maven-compiler-plugin
│       ├── compile
│       │   └── default-compile
│       │       ├── createdFiles.lst
│       │       └── inputFiles.lst
│       └── testCompile
│           └── default-testCompile
│               ├── createdFiles.lst
│               └── inputFiles.lst
├── surefire-reports
│   ├── by.rakovets.example.AppTest.txt
│   └── TEST-by.rakovets.example.AppTest.xml
└── test-classes
    └── by
        └── rakovets
            └── example
                └── AppTest.class

Теперь запустим приложение. Для этого необходимо запустить следующую команду:

java --class-path ./target/classes by.rakovets.example.App

В результате получим, следующий результат:

Output
Hello World!

7. Документирование проекта

Рассмотрим, как создать документацию для проекта с помощью Apache Maven. В качестве проекта будет использоваться проект сгенерированный с помощью archetype maven-archetype-quickstart.

mvn clean site

В результате получим примерно следующий результат:

Output
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:maven-example >------------------
[INFO] Building maven-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ maven-example ---
[INFO] Deleting   /home/rakovetsmaven/maven-example/target
[INFO]
[INFO] --- maven-site-plugin:3.7.1:site (default-site) @ maven-example ---
[INFO] configuring report plugin org.apache.maven.plugins:maven-project-info-reports-plugin:3.0.0
[INFO] 15 reports detected for maven-project-info-reports-plugin:3.0.0: ci-management, dependencies, dependency-info, dependency-management, distribution-management, index, issue-management, licenses, mailing-lists, modules, plugin-management, plugins, scm, summary, team
[INFO] Rendering site with default locale English (en)
[INFO] Relativizing decoration links with respect to localized project URL: http://www.example.com
[INFO] Rendering content with org.apache.maven.skins:maven-default-skin:jar:1.2 skin.
[INFO] Generating "Dependencies" report  --- maven-project-info-reports-plugin:3.0.0:dependencies
[INFO] Generating "Dependency Information" report --- maven-project-info-reports-plugin:3.0.0:dependency-info
[INFO] Generating "About" report         --- maven-project-info-reports-plugin:3.0.0:index
[INFO] Generating "Plugin Management" report --- maven-project-info-reports-plugin:3.0.0:plugin-management
[INFO] Generating "Plugins" report       --- maven-project-info-reports-plugin:3.0.0:plugins
[INFO] Generating "Summary" report       --- maven-project-info-reports-plugin:3.0.0:summary
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.483 s
[INFO] Finished at: 2021-10-15T07:24:25+03:00
[INFO] ------------------------------------------------------------------------

В итоге будет сгенерирована следующая документация:

Структура директории ./target/site для проекта
target/site/
├── css
│     ├── maven-base.css
│     ├── maven-theme.css
│     ├── print.css
│     └── site.css
├── dependencies.html
├── dependency-info.html
├── images
│     ├── close.gif
│     ├── collapsed.gif
│     ├── expanded.gif
│     ├── external.png
│     ├── icon_error_sml.gif
│     ├── icon_info_sml.gif
│     ├── icon_success_sml.gif
│     ├── icon_warning_sml.gif
│     ├── logos
│     │     ├── build-by-maven-black.png
│     │     ├── build-by-maven-white.png
│     │     └── maven-feather.png
│     └── newwindow.png
├── index.html
├── plugin-management.html
├── plugins.html
├── project-info.html
└── summary.html

Откроем с помощью браузера target/site/index.html.

Окно создания информации о проекте

Apache Maven создаёт документацию с помощью механизма documentation-processing, который называется Doxia, позволяющий сводить различные форматы в один документ. Подробнее: Maven Doxia

8. Repositories

8.1. Artifacts

Artifact (артефакт) - это набор активов вашего проекта, который собираете для тестирования, развертывания или распространения программного решения или его части. Примерами являются набор скомпилированных java-классов или java-приложение, упакованное в java-архив (.jar), web-приложение в виде структуры директорий или архив web-приложения (.war) и т.д.

Artifact может быть архивом или структурой директорий, которая включает следующие структурные элементы:

  • Файлы после компилирования одного или нескольких модулей

  • Библиотеки, включенные в зависимости модулей

  • Набор ресурсов (web-страницы, изображения, файлы дескрипторов и т.д.)

  • Прочие артефакты

  • Отдельные файлы, директории и архивы.

artifacts

Чаще всего конечным продуктом получаемым после сборки java-проекта, независимо от того собирается он вручную или инструментами сборки, является jar или war-file. Их обычно и называют artifacts (артефакты), иногда java-libraries (java-библиотеками).

Решения большинства задач и проблем в Java уже реализованно другими разработчиками/командами/компаниями по средствам этих artifacts и свободно распространяется под Open Source лицензиями. Соответственно, лучше использовать уже готовые и проверенные решения, чем писать свои решения с нуля. Но для этого необходим механизм распространения artifacts. Такой механизм предоставляет Apache Maven.

8.2. Repositories

При работе с Apache Maven под repository (репозиторием) понимается директорию, где хранятся все .jar, .war, библиотеки, плагины и любые артефакты, которыми Maven может воспользоваться.

Существует cледующие типы репозиториев:

  • local (локальные)

  • remote (удалённые)

8.2.1. Local repository

Local repository (Локальный репозиторий) – это директория, которая хранится на локальном компьютере (т.е. компьютере пользователя). Она создаётся в момент первого выполнения любой команды Apache Maven.

Local repository хранит все dependencies проекта (библиотеки, плагины и т.д.). Когда выполняется сборка проекта с помощью Apache Maven, то все dependencies (их JAR-файлы) автоматически загружаются в local repository. Это помогает избежать использование ссылок на remote repository при каждой сборке проекта.

По умолчанию, local repository создаётся Apache Maven в директории ${user.home}/.m2/repository и зависит от ОС (Операционной Системы):

OS Filepath

Linux

/home/<username>/.m2/repository

MacOS

/Users/<username>/.m2/repository

Windows

C:\Users\<username>\.m2\repository

Для того, что бы изменить директорию необходимо указать её в конфигурационном файле Apache Maven: settings.xml, который находится в директории ${user.home}/.m2/conf и зависит от ОС:

OS Filepath

Linux

/home/<username>/.m2/conf/setting.xml

MacOS

/Users/<username>/.m2/conf/setting.xml

Windows

C:\Users\<username>\.m2\conf\setting.xml

Выглядит это следующим образом:

settings.xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
        http://maven.apache.org/xsd/settings-1.0.0.xsd">
    ...
    <localRepository>/home/rakovets/libs</localRepository>
    ...
</settings>

Когда выполняются команды Apache Maven, то все зависимости, используемые для этой команды, будут автоматически загружены в локальный репозиторий.

8.3. Remote repository

Условно remote repositories можно разделить на 3 типа:

  • central (центральные) - публичный repository предоставляемый сообществом Apache Maven.

  • external (внешний) - публичный repository предоставляемый различными разработчиками/командами/компаниями.

  • internal (внутренний) - приватный repository разработчика/команды/компании, чаще всего доступный только в локальной сети.

maven repositories

8.3.1. Central repository

Central repository (центральный репозиторий) – это repository, который обеспечивается сообществом Apache Maven. Он содержит огромное количество часто используемых библиотек.

Если Apache Maven не может найти зависимости в local repository, то автоматически начинается поиск необходимых файлов в central repository по адресу https://repo1.maven.org/maven2/.

8.3.2. Remote repository

Иногда, Apache Maven не может найти необходимые зависимости в central repository. В этом случае процесс сборки прерывается и в консоль выводится сообщение об ошибке.

Для того, что бы предотвратить подобную ситуацию, в Apache Maven предусмотрен механизм remote repository, который является repository определяемым самим разработчиком. Там могут храниться все необходимые зависимости.

Для того, что бы настроить remote repository, используют два подхода:

  • определить remote repository в settings.xml

  • определить remote repository в pom.xml

необходимо внести следующие изменения в файл pom.xml.

<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>by.rakovets.example</groupId>
    <artifactId>maven-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>by.rakovets.example</groupId>
            <artifactId>maven-private-example</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>rakovets-external</id>
            <url>https://maven.rakovets.by/maven2/public</url>
        </repository>
        <repository>
            <id>rakovets-internal</id>
            <url>https://maven.rakovets.by/maven2/private</url>
        </repository>
    </repositories>
</project>

8.3.3. Порядок поиска зависимостей Maven

Когда выполняется сборка проекта c помощью Apache Maven, автоматически начинается поиск необходимых зависимостей в следующем порядке:

  1. Поиск зависимостей в local repository. Если зависимости не обнаружены, происходит переход к шагу 2.

  2. Поиск зависимостей в central repository. Если они не обнаружены и remote repository определён, то происходит переход к шагу 4.

  3. Если удалённый репозиторий не определён, то процесс сборки прекращается и выводится сообщение об ошибке.

  4. Поиск зависимостей на remote repository, если они найдены, то происходит их загрузка в local repository, если нет – выводится сообщение об ошибке.

maven build search repository order

9. Dependencies

В Maven dependency (зависимостью) является другой artifact - .jar, .war и т.д. - который нужен вашему текущему проекту для компиляции, сборки, тестирования и/или запуска. Dependencies собраны в pom.xml файле внутри тега <dependencies>.

Когда запускается сборку или выполняете goal, эти dependencies разрешаются, а затем загружаются из local repository. Если их там нет, Apache Maven загрузит их из remote repository и сохранит в local repository. Можно также вручную установить зависимости.

9.1. Добавление dependencies

Рассмотрим пример, который демонстрирует добавление зависимостей для проекта:

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.5.RELEASE</version>
    </dependency>
</dependencies>

Если pom.xml указывает на множество одинаковых артефактов из одной groupId, следует использовать properties, чтобы указать версию для artifacts для упрощения поддержки версий.

<project>
    ...

    <properties>
        <junit.version>4.12</junit.version>
        <spring.version>4.3.5.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
</project>

9.2. External dependencies

Иногда приходится использовать dependencies, которых нет в maven repository (ни в local, ни в central, ни в remote). В таком случае можно использовать jar-файлы для этих dependencies, поместив их в директорию проекта (например: lib) и настроить external dependency (внешнюю зависимость). Например:

<dependency>
    <groupId>maven-external-dependency-example</groupId>
    <artifactId>maven-external-dependency-example</artifactId>
    <scope>system</scope>
    <version>1.0</version>
    <systemPath>${basedir}/war/WEB-INF/lib/maven-external-dependency-example.jar</systemPath>
</dependency>
  • groupId, artifactId - задается именем dependency.

  • scope - устанавливается как system.

  • systemPath - место расположения файла с данной зависимостью.

9.3. Dependency tree

Используя команду mvn dependency:tree, можно просмотреть список всех зависимостей вашего проекта - transitively (транзитивно). Transitive dependency (транзитивная зависимость) означает, что если A зависит от B, а B зависит от C, то A зависит как от B, так и от C.

Transitivity (транзитивность) создает очень серьезную проблему, когда разные версии одних и тех же artifacts включаются разными dependencies. Это может вызвать проблему version mismatch (несоответствия версий) во время выполнения. В этом случае команда dependency:tree очень полезна при разрешении конфликтов dependencies.

Если для проекта созданному с помощью archetype maven-archetype-quickstart выполнить команду:

mvn dependency:tree

то получим следующий вывод:

Output
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:maven-example >------------------
[INFO] Building maven-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ maven-example ---
[INFO] by.rakovets.example:maven-example:jar:1.0-SNAPSHOT
[INFO] \- junit:junit:jar:4.11:test
[INFO]    \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.679 s
[INFO] Finished at: 2021-10-16T06:28:19+03:00
[INFO] ------------------------------------------------------------------------

Таким образом можно увидеть все transitive dependencies. Для данного случая можно увидеть что junit:junit:4.11, который используется для тестирования, сам зависит от org.hamcrest:hamcrest-core:1.3.

9.4. Dependency Exclusion

Помимо проблемы version mismatch (несоответствия версий), вызванной transitive dependencies (транзитивной зависимостью), может быть version mismatch между artifacts проекта и artifacts от платформы развертывания (т.е. ПО куда устанавливается разработанное приложение), например Apache Tomcat, WildFly и т.д.

Чтобы решить такие проблемы version mismatch, Apache Maven предоставляет тег <exclusion>, чтобы разорвать transitive dependency.

Например, если есть dependency JUnit 4.12 и dependency DBUnit 2.4.9, и если нужно будет удалить зависимость JUnit 3.8.2, то это можно сделать с помощью тега <exclusion>.

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.dbunit</groupId>
        <artifactId>dbunit</artifactId>
        <version>2.4.9</version>
        <scope>test</scope>
        <exclusions>
            <!--Exclude transitive dependency to JUnit-3.8.2 -->
            <exclusion>
                <artifactId>junit</artifactId>
                <groupId>junit</groupId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

9.5. Dependency scopes

Dependencies имеют область видимости (scope). Scope позволяет указать Apache Maven когда и для чего нужна эта dependency. Всего существует шесть областей видимости:

  • compile — область видимости по умолчанию. Зависимости с этим scope будут доступны и во время сборки и во время тестирования и их даже добавят в конечный пакет, чтобы они были доступны и во время исполнения. Более того, maven распространит их дальше и сделает доступными в зависимых пакетах.

  • provided — почти как compile, но в пакет зависимость добавлена не будет. Предполагается что данные библиотеки будут предоставлены средой выполнения, например контейнером сервлетов. Каноничный пример такой зависимости — Servlet API, конкретная реализация которых предоставляется контейнером сервлетов.

  • runtime — антипод provided. Означает зависимость, которая требуется для исполнения/тестирования кода, но не для его сборки. Зависимости из этого scope так же будут добавлены в пакет.

  • test — зависимости, которые нужны только и исключительно для тестов, например JUnit.

  • system — зависимость, которая присутствует в среде Java всегда, тем или иным путём. Maven не будет пытаться предоставить этот артефакт или класть его в пакет итд.

  • import — используется для импорта зависимостей из других артефактов и управлением зависимостями в сложных пакетах, состоящих из нескольких артефактов.

Table 2. Dependency scopes
Result scope Compile classpath Test classpath Runtime classpath Lookup repository

compile

+

+

+

+

provided

+

+

-

+

runtime

-

+

+

+

test

-

+

-

+

system

+

+

-

-

import

Maven 2.0.9 or later, replace POM with <dependencyManagement>

Пример зависимостей с разными scopes:
<dependencies>
    <!-- Lombok code generator -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.22</version>
        <scope>provided</scope>
    </dependency>

    <!-- Logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.32</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.14.1</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.14.1</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.14.1</version>
        <scope>runtime</scope>
    </dependency>

    <!-- Unit testing -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.8.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>
  • org.projectlombok:lombok — утилита для генерации кода, работающая только во время компиляции, поэтому scope — provided

  • org.slf4j:slf4j-api — API для ведения логов, проект с ним собирается, тестируется и работает, поэтому scope — compile.

  • org.apache.logging.log4j:log4j-slf4j-impl — реализация Slf4j поверх log4j2, проект не ссылается напрямую на эту библиотеку и использует её только посредством Slf4j, поэтому scope — runtime.

  • org.junit.jupiter:junit-jupiter — фреймворк для unit-тестирования, он нужен только во время исполнения тестов, поэтому scope — test.

Области видимости system и import используются редко.

9.6. Artifact Version Ranges

Включая dependency, можно указать диапазон версий для любого artifact. Чтобы указать диапазон версий, можно использовать следующие символы:

  • круглые скобоки ( и ) указывают на исключение границ из диапазона

  • квадратные скобки [ и ] указывают на включение границ в диапазон

  • запятая , используется для разделения подмножеств

Table 3. Примеры диапазона версий
Диапазон Что означает

1.2

Версия равна 1.2 или начинается с 1.2, т.е. x >= 1.2

(, 1.2]

Любая версия ниже 1.2, включая версию 1.2, т.е. x <= 1.2

(, 1.2)

Любая версия ниже 1.2, не включая версию 1.2, т.е. x < 1.2

[1.2]

Только версия 1.2, т.е. x == 1.2

[1.2,)

Любая версия выше 1.2, включая версию 1.2, т.е. x >= 1.2

(1.2,)

Любая версия выше 1.2, не включая версию 1.2, т.е. x > 1.2

(1.2,2.2)

Версия от 1.2 до 2.2, не включая версии 1.2 и 2.2, т.е. 1.2 < x < 2.2

[1.2,2.2]

Версия от 1.2 до 2.2, включая версии 1.2 и 2.2, т.е. 1.2 <= x <= 2.2

(, 1.2], [2.2,)

Версия ниже 1.2 или выше 2.2, включая версии 1.2 и 2.2, т.е. x <= 1.2 OR x >= 2.2

10. Snapshots

Любое большое приложение состоит из нескольких модулей и, чаще всего над каждым модулем программы работает отдельная команда. Например, одна команда работает над бизнес-логикой приложения, и они используют проект business-logic, конечным artifact является business-logic.jar, а другая команда работает на внешним видом приложения и разрабатывает проект web-app, конечным artifact является web-app.jar.

В этом случае может случиться такая ситуация, когда команда, которая работает над бизнес-логикой, выпускает обновления каждую неделю и выкладывает их в remote repository

Таким образом, если эта команда часто выкладывает обновления, то можем произойти следующее:

  • команда бизнес-логики должна уведомлять команду, разрабатывающую web-app, когда именно они будут выкладывать обновления;

  • команда web-app должна обновлять свой файл pom.xml для того, чтобы иметь текущую версию продукта.

Для того, что исправить эту ситуацию используется концепция snapshot.

10.1. Snapshot version

Snapshot – это специальная версия, которая показывает текущую рабочую копию. При каждой сборке Apache Maven проверяет наличие новой snapshot версии на удалённом репозитории.

В этом случае, команда business-logic будет выпускать snapshot своего обновления на репозиторий в виде business-logic:1.0-SNAPSHOT замещая предыдущий jar-файл.

В случае со snapshot, Apache Maven автоматически будет подтягивать последний snapshot (business-logic:1.0-SNAPSHOT) каждый раз, когда команда web-app будет выполнять сборку своего проекта.

Вот как это выглядит в pom.xml файле:

pom.xml для web-app
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example.maven.snapshot</groupId>
    <artifactId>web-app</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>by.rakovets.example.maven.snapshot</groupId>
            <artifactId>business-logic</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
pom.xml для business-logic
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>by.rakovets.example.maven.snapshot</groupId>
    <artifactId>business-logic</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

Для того чтобы подтянуть крайний snapshot необходимо использовать -U в каждой команде.

mvn clean package -U

10.2. Release version

В случае с release version (релизной версией), т.е любой версией не имеющей постфикса -SNAPSHOT, если Apache Maven однажды загрузил такую версию, например business-logic:1.0, то он больше не будет пытаться загрузить новую версию (в текущем примере 1.0) из repository, потому что он считает что данная версия является неизменяемой (релизной). Для того, что бы скачать свежую версию, которую команда business-logic выпустила недавно, необходимо обновить версию в pom.xml для web-app на выпущенную версию командой business-logic (например до версии 1.1).

pom.xml для web-app использующий версию 1.0 для business-logic
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example.maven.snapshot</groupId>
    <artifactId>web-app</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>by.rakovets.example.maven.snapshot</groupId>
            <artifactId>business-logic</artifactId>
            <version>1.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
pom.xml для business-logic версии 1.1
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>by.rakovets.example.maven.snapshot</groupId>
    <artifactId>business-logic</artifactId>
    <version>1.1</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

Обновляем версию:

pom.xml для web-app использующий версию 1.1 для business-logic
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example.maven.snapshot</groupId>
    <artifactId>web-app</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>by.rakovets.example.maven.snapshot</groupId>
            <artifactId>business-logic</artifactId>
            <version>1.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

11. Профиль сборки

Build profile (профиль сборки) – это множество настроек, которые могут быть использованы для установки или перезаписи стандартных значений сборки Apache Maven. Используя профиль сборки, можно настраивать сборку для различных окружений, таких как dev или prod.

Профили настраиваются в файле pom.xml с помощью элементов activeProfiles/profiles и запускаются различными методами. Профили изменяют файл pom.xml во время сборки и используются для передачи параметров различным целевым окружениям, например, в директорию сервера базы данных в продакшн, разработку и тестирования.

11.1. Типы профилей сборки

В Apache Maven существует три основных типа профилей сборки:

Тип Описание

Per Project

Определяется в POM файле, pom.xml

Per User

Определяется в настройках Maven – xml файл (%USER_HOME%/.m2/settings.xml)

Global

Определяется в глобальных настройках – xml файл (%M2_HOME%/conf/settings.xml)

11.2. Активация профиля

Профиль сборки Apache Maven может быть активирован различными способами:

  • С использованием команды в консоли

  • С помощью настроек Apache Maven

  • С помощью переменных окружения

  • С помощью настроек ОС

  • С помощью существующих, отсутствующих файлов.

Для понимания того, как это работает на практике, рассмотрим следующий пример:

Структура проекта
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── by
    │   │       └── rakovets
    │   │           └── example
    │   │               └── App.java
    │   └── resources
    │       ├── environment.prod.properties
    │       ├── environment.properties
    │       └── environment.test.properties
    └── test
        └── java
            └── by
                └── rakovets
                    └── example
                        └── AppTest.java

В директории scr/main/resources находятся файлы для настройки трёх различных окружений:

Имя файла Описание

environment.properties

Стандартная конфигурация. Используется по умолчанию.

environment.test.properties

Тестовая конфигурация. Когда используется профиль test.

environment.prod.properties

Продакшн конфигурация. Когда используется профиль prod.

Содержимое файлов:

environment.properties
environment=dev
environment.test.properties
environment=test
environment.prod.properties
environment=prod

11.3. Явная активация профиля (команда в консоли)

В примере, приведённом ниже будет прикреплена задача maven-antrun-plugin:run к фазе test. Это позволит получать текстовые сообщения для различных профилей. Используя файл pom.xml для определения различных профилей и активации различные профили с помощью команд в консоли.

Пример:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example</groupId>
    <artifactId>maven-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <id>test</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-antrun-plugin</artifactId>
                        <version>1.1</version>
                        <executions>
                            <execution>
                                <phase>test</phase>
                                <goals>
                                    <goal>run</goal>
                                </goals>
                                <configuration>
                                    <tasks>
                                        <echo>Using environment.test.properties</echo>
                                        <copy file="src/main/resources/environment.test.properties" tofile="${project.build.outputDirectory}/environment.properties"/>
                                    </tasks>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

Выполним следующую команду в терминале:

mvn test -Ptest

В результате получится, примерно, следующий результат:

[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:maven-example >------------------
[INFO] Building maven-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 3 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ maven-example ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/rakovets/maven-example/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven-example/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ maven-example ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/rakovets/maven-example/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ maven-example ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running by.rakovets.example.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.017 s - in by.rakovets.example.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (default) @ maven-example ---
[INFO] Executing tasks
     [echo] Using environment.test.properties
     [copy] Copying 1 file to /home/rakovets/maven-example/target/classes
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.490 s
[INFO] Finished at: 2021-10-17T08:39:45+03:00
[INFO] -----------------------------------------------------------------------

11.4. Активация профиля с помощью настроек Apache Maven

Для начала необходимо открыть файл settings.xml, который находится в директории %USER_HOME%/.m2. Если файла там нет – его необходимо создать.

Активация тестового профиля с помощью элемента activeProfile, как показано в примере ниже:

<settings xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <activeProfiles>
        <activeProfile>test</activeProfile>
    </activeProfiles>
</settings>

Теперь выполним команду:

mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:maven-example >------------------
[INFO] Building maven-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 3 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ maven-example ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven-example/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ maven-example ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ maven-example ---
[INFO]
[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running by.rakovets.example.AppTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.018 s - in by.rakovets.example.AppTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (default) @ maven-example ---
[INFO] Executing tasks
     [echo] Using environment.test.properties
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.075 s
[INFO] Finished at: 2021-10-17T08:45:31+03:00
[INFO] -----------------------------------------------------------------------

11.5. Активация профиля с помощью переменных окружения

Необходимо удалить файл settings.xml, и изменить профиль test в файле pom.xml. Добавить элемент activation.

Профиль test запустит системное свойство environment, которое определенно, как значение test.

Пример:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example</groupId>
    <artifactId>maven-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <id>test</id>
            <activation>
                <property>
                    <name>environment</name>
                    <value>test</value>
                </property>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-antrun-plugin</artifactId>
                        <version>1.1</version>
                        <executions>
                            <execution>
                                <phase>test</phase>
                                <goals>
                                    <goal>run</goal>
                                </goals>
                                <configuration>
                                    <tasks>
                                        <echo>Using environment.test.properties</echo>
                                    </tasks>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

Теперь выполним команду:

mvn test

В результате будет получен, примерно, следующий результат:

[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:maven-example >------------------
[INFO] Building maven-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 3 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-example ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven-example/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ maven-example ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ maven-example ---
[INFO] Surefire report directory: /home/rakovets/maven-example/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running by.rakovets.example.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.021 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (default) @ maven-example ---
[INFO] Executing tasks
     [echo] Using environment.test.properties
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.568 s
[INFO] Finished at: 2021-10-17T09:05:35+03:00
[INFO] ------------------------------------------------------------------------

11.6. Активация профиля с помощью ОС

Для активации профиля с помощью ОС необходимо изменить тип активации в файле pom.xml на следующий:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example</groupId>
    <artifactId>maven-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <id>test</id>
            <activation>
                <os>
                    <name>linux</name>
                    <family>unix</family>
                    <arch>amd64</arch>
                </os>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-antrun-plugin</artifactId>
                        <version>1.1</version>
                        <executions>
                            <execution>
                                <phase>test</phase>
                                <goals>
                                    <goal>run</goal>
                                </goals>
                                <configuration>
                                    <tasks>
                                        <echo>Using environment.test.properties</echo>
                                    </tasks>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

Выполнить команду:

mvn test

В результате будет получен, примерно, следующий результат:

[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:maven-example >------------------
[INFO] Building maven-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven-example/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-example ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven-example/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ maven-example ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ maven-example ---
[INFO] Surefire report directory: /home/rakovets/maven-example/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running by.rakovets.example.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.021 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (default) @ maven-example ---
[INFO] Executing tasks
     [echo] Using environment.test.properties
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.585 s
[INFO] Finished at: 2021-10-19T07:19:17+03:00
[INFO] ------------------------------------------------------------------------

11.7. Активация с помощью присутствующих или отсутствующих файлов

В примере, приведённом ниже, активация профиля произойдёт в случае отсутствия ./application.properties

Пример:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example</groupId>
    <artifactId>maven-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <id>test</id>
            <activation>
                <file>
                    <missing>./application.properties</missing>
                </file>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-antrun-plugin</artifactId>
                        <version>1.1</version>
                        <executions>
                            <execution>
                                <phase>test</phase>
                                <goals>
                                    <goal>run</goal>
                                </goals>
                                <configuration>
                                    <tasks>
                                        <echo>Using environment.test.properties</echo>
                                    </tasks>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

Выполнить команду:

mvn test

В результате будет получен, примерно, следующий результат:

[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< by.rakovets.example:maven-example >------------------
[INFO] Building maven-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven-example/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-example ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-example ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven-example/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ maven-example ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ maven-example ---
[INFO] Surefire report directory: /home/rakovets/maven-example/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running by.rakovets.example.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.022 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] --- maven-antrun-plugin:1.1:run (default) @ maven-example ---
[INFO] Executing tasks
     [echo] Using environment.test.properties
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.582 s
[INFO] Finished at: 2021-10-19T07:22:51+03:00
[INFO] ------------------------------------------------------------------------

12. Создание Web-проекта

12.1. Создание проекта

Для того чтобы создать простой веб-проект, можно использовать archetype maven-archetype-webapp. Для этого нужно выполнить следующую команду:

mvn archetype:generate \
        -DgroupId=by.rakovets.example \
        -DartifactId=maven-web-project \
        -DarchetypeArtifactId=maven-archetype-webapp \
        -DarchetypeVersion=1.4 \
        -DinteractiveMode=false

В итоге получим следующий результат:

Output
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:3.2.0:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:3.2.0:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO]
[INFO] --- maven-archetype-plugin:3.2.0:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Batch mode
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: maven-archetype-webapp:1.4
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: by.rakovets.example
[INFO] Parameter: artifactId, Value: maven-web-project
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: by.rakovets.example
[INFO] Parameter: packageInPathFormat, Value: by/rakovets/example
[INFO] Parameter: package, Value: by.rakovets.example
[INFO] Parameter: groupId, Value: by.rakovets.example
[INFO] Parameter: artifactId, Value: maven-web-project
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Project created from Archetype in dir: /home/rakovets/maven/maven-web-project
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.352 s
[INFO] Finished at: 2021-10-20T05:05:54+03:00
[INFO] ------------------------------------------------------------------------

Сгенерированный проект будет выглядеть следующим образом:

Структура проекта
maven-web-project/
├── pom.xml
└── src
    └── main
        └── webapp
            ├── index.jsp
            └── WEB-INF
                └── web.xml
pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example</groupId>
    <artifactId>maven-web-project</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>maven-web-project Maven Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>maven-web-project</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>
src/webapp/index.jsp
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>

12.2. Запуск приложения

Выполним команду:

mvn clean package

В итоге получим следующий результат:

[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< by.rakovets.example:maven-web-project >----------------
[INFO] Building maven-web-project Maven Webapp 1.0-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ maven-web-project ---
[INFO] Deleting /home/rakovets/maven/maven-web-project/target
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:resources (default-resources) @ maven-web-project ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven/maven-web-project/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ maven-web-project ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-resources-plugin:3.0.2:testResources (default-testResources) @ maven-web-project ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven/maven-web-project/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ maven-web-project ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ maven-web-project ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-war-plugin:3.2.2:war (default-war) @ maven-web-project ---
[INFO] Packaging webapp
[INFO] Assembling webapp [maven-web-project] in [/home/rakovets/maven/maven-web-project/target/maven-web-project]
[INFO] Processing war project
[INFO] Copying webapp resources [/home/rakovets/maven/maven-web-project/src/main/webapp]
[INFO] Webapp assembled in [9 msecs]
[INFO] Building war: /home/rakovets/maven/maven-web-project/target/maven-web-project.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.689 s
[INFO] Finished at: 2021-10-20T05:14:00+03:00
[INFO] ------------------------------------------------------------------------

Запустим приложение с помощью контейнера сервлетов (например: Apache Tomcat) и получим следующий результат:

Hello World Maven
Web-страница

13. Автоматизация сборки

Автоматизация сборки определяет сценарий, в котором процесс сборки зависимого проекта запускается после успешного завершения сборки проекта, чтобы обеспечить стабильность зависимых проектов.

Предположим, что команда разрабатывает проект bus-core-api, от которого зависят два других проекта: app-web-ui и app-desktop-ui.

Структура директории с проектами
.
├── app-desktop-ui
├── app-web-ui
└── bus-core-api
pom.xml для bus-core-api
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example.maven</groupId>
    <artifactId>bus-core-api</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

Проект app-web-ui использует версию 1.0-SNAPSHOT проекта bus-core-api.

pom.xml для app-web-ui
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example.maven</groupId>
    <artifactId>app-web-ui</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>by.rakovets.example.maven</groupId>
            <artifactId>bus-core-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

Проект app-desktop-ui использует версию 1.0-SNAPSHOT проекта bus-core-api.

<project xmlns = "http://maven.apache.org/POM/4.0.0"
        xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example.maven</groupId>
    <artifactId>app-desktop-ui</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>by.rakovets.example.maven</groupId>
            <artifactId>bus-core-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

Теперь команды проектов app-web-ui и app-desktop-ui хочет, чтобы процесс их сборки начинался всякий раз, когда изменяется проект bus-core-api.

Использование snapshot гарантирует, что будет использоваться последняя версия проекта bus-core-api, но для того, что бы это происходило автоматически нужно сделать что-то дополнительное.

Можно действовать следующими двумя способами:

  • Использовать Apache Maven
    Добавить goal пост-сборки в pom.xml bus-core-api для запуска сборок app-web-ui и app-desktop-ui.

  • Использовать CI инструменты
    Continuous Integration (CI, непрерывной интеграции) инструмент, например Jenkins, позволяет автоматически управлять сборкой (и не только).

13.1. Использование Apache Maven

Warning
Приведенный пример является синтетическим, так как для такой задачи обычно применяют либо многомодульный Apache Maven проект с дальнейшим deploy артефактов в remote repository, либо же CI инструменты.

Для проект bus-core-api pom.xml используем maven-invoker-plugin.

<project xmlns = "http://maven.apache.org/POM/4.0.0"
        xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>by.rakovets.example.maven</groupId>
    <artifactId>bus-core-api</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-invoker-plugin</artifactId>
                <version>3.2.2</version>
                <configuration>
                    <projectsDirectory>..</projectsDirectory>
                    <pomIncludes>
                        <pomInclude>app-web-ui/pom.xml</pomInclude>
                        <pomInclude>app-desktop-ui/pom.xml</pomInclude>
                    </pomIncludes>
                </configuration>
                <executions>
                    <execution>
                        <id>build</id>
                        <phase>install</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

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

mvn clean install

Apache Maven начнет сборку проекта bus-core-api.

[INFO] Scanning for projects...
[INFO]
[INFO] ---------------< by.rakovets.example.maven:bus-core-api >---------------
[INFO] Building bus-core-api 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ bus-core-api ---
[INFO] Deleting /home/rakovets/maven/bus-core-api/target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ bus-core-api ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven/bus-core-api/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ bus-core-api ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ bus-core-api ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven/bus-core-api/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ bus-core-api ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ bus-core-api ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ bus-core-api ---
[INFO] Building jar: /home/rakovets/maven/bus-core-api/target/bus-core-api-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ bus-core-api ---
[INFO] Installing /home/rakovets/maven/bus-core-api/target/bus-core-api-1.0-SNAPSHOT.jar to /home/rakovets/.m2/repository/by/rakovets/example/maven/bus-core-api/1.0-SNAPSHOT/bus-core-api-1.0-SNAPSHOT.jar
[INFO] Installing /home/rakovets/maven/bus-core-api/pom.xml to /home/rakovets/.m2/repository/by/rakovets/example/maven/bus-core-api/1.0-SNAPSHOT/bus-core-api-1.0-SNAPSHOT.pom
[INFO]
[INFO] --- maven-invoker-plugin:3.2.2:run (build) @ bus-core-api ---
[WARNING] Filtering of parent/child POMs is not supported without cloning the projects
[INFO] Building: app-web-ui/pom.xml
[INFO]           app-web-ui/pom.xml ............................... SUCCESS (1.2 s)
[INFO] Building: app-desktop-ui/pom.xml
[INFO]           app-desktop-ui/pom.xml ........................... SUCCESS (1.1 s)
[INFO] -------------------------------------------------
[INFO] Build Summary:
[INFO]   Passed: 2, Failed: 0, Errors: 0, Skipped: 0
[INFO] -------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.102 s
[INFO] Finished at: 2021-10-20T20:49:26+03:00
[INFO] ------------------------------------------------------------------------

После успешной сборка bus-core-api будет успешной, Apache Maven начнет сборку проекта app-web-ui.

app-web-ui/build.log
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< by.rakovets.example.maven:app-web-ui >----------------
[INFO] Building app-web-ui 1.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ app-web-ui ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven/app-web-ui/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ app-web-ui ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ app-web-ui ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven/app-web-ui/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ app-web-ui ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ app-web-ui ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ app-web-ui ---
[INFO] Building jar: /home/rakovets/maven/app-web-ui/target/app-web-ui-1.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.488 s
[INFO] Finished at: 2021-10-20T20:49:25+03:00
[INFO] ------------------------------------------------------------------------

Как только сборка app-web-ui будет успешной, Apache Maven начнет сборку проекта app-desktop-ui.

app-desktop-ui/build.log
[INFO] Scanning for projects...
[INFO]
[INFO] --------------< by.rakovets.example.maven:app-desktop-ui >--------------
[INFO] Building app-desktop-ui 1.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ app-desktop-ui ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven/app-desktop-ui/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ app-desktop-ui ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ app-desktop-ui ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/rakovets/maven/app-desktop-ui/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ app-desktop-ui ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ app-desktop-ui ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ app-desktop-ui ---
[INFO] Building jar: /home/rakovets/maven/app-desktop-ui/target/app-desktop-ui-1.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.485 s
[INFO] Finished at: 2021-10-20T20:49:26+03:00
[INFO] ------------------------------------------------------------------------

13.2. Использование CI инструментов с Apache Maven

Использование CI инструментов более предпочтительно для разработчиков. Jenkins — это один из инструментов CI (непрерывной интеграции), написанный на Java, который находится в контейнере сервлетов (Apache Tomcat). Jenkins автоматически управляет автоматизацией сборки с помощью Apache Maven (и не только его).

Jenkins рассматривает каждый проект как job (задание). После того как код проекта отправлен в Git (или в любую другую систему контроля версий), можно настроить Jenkins на какие-то triggers, срабатывание которых будет запускать job, и как только она завершается, он автоматически запускает другие зависимые jobs (в текущем примере, сборку других зависимых проектов).

14. Автоматизация развёртывания

При разработке проекта Continuous Deployment (CD, процесс развёртывания) состоит из следующих шагов:

  • Проверка всего кода проекта в системе контроля версий.

  • Скачивание всего исходного кода из системы контроля версий.

  • Сборка приложения.

  • Получение WAR или EAR файла проекта.

  • Развёртывание файла на сервере.

  • Обновление документации и обновление номера версии приложения.

14.1. Проблема

Обычно в процессе развёртывания участвуют много человек. Одна команда проверяет код, вторая выполняет сборку и т.д. Если всё выполнять вручную, какой-то из моментов может быть упущен и т.д.

14.2. Решение

Здесь приходит на помощь автоматизация развёртывания с помощью комбинирования:

  • Сборки и релиза проекта с помощью Apache Maven;

  • Использование системы контроля версий (например, Git c git-hosting на GitHub) для работы с кодом;

  • Использования систем управления удалёнными репозиториями (например, GitHub Packages).

Warning
Данный пример не будет работать без предварительной настройки Apache Maven и remote repository. Что бы сделать необходимую настройку следует обратиться по ссылке Working with the Apache Maven registry

14.3. Обновление pom.xml проекта

Для автоматизирования релиза продукта используется плагин maven-release-plugin.

pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>by.rakovets.example</groupId>
    <artifactId>maven-release-plugin-example</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <scm>
        <url>https://github.com/rakovets/maven-release-plugin-example</url>
        <connection>scm:git:https://github.com/rakovets/maven-release-plugin-example.git</connection>
        <tag>HEAD</tag>
    </scm>

    <distributionManagement>
        <repository>
            <id>github</id>
            <name>GitHub Rakovets Apache Maven Packages</name>
            <url>https://maven.pkg.github.com/rakovets/maven-release-plugin-example</url>
        </repository>
    </distributionManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-release-plugin</artifactId>
                <configuration>
                    <useReleaseProfile>false</useReleaseProfile>
                    <goals>deploy</goals>
                    <scmCommentPrefix>[maven-release-plugin]-</scmCommentPrefix>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

В этом pom.xml файле использовались следующие важные элементы:

  • SCM
    Определяет расположение системы контроля версий, в которой ApacheMaven выполнит проверку исходного кода.

  • Repositories
    Место хранения JAR, WAR, или других артефактов, которые будут отправлены на хранение в случае успешной сборки.

  • Plugin
    Элемент maven-release-plugin сконфигурирован для автоматизации процесса развёртывания.

С помощью maven-release-plugin Apache Maven выполняет различные задачи.

Рассмотрим структуру проекта:

  1. Project structure

.
├── pom.xml
└── src
    └── main
        └── java
            └── Application.java
src/main/java/Application.java
public class Application {
    public static void main(String[] args) {
        System.out.println("Hello maven-release-plugin");
    }
}
git log --oneline
fff3392 (HEAD -> master, origin/master, origin/HEAD) feat: init project

14.3.1. release:prepare

mvn release:prepare

Выполняет множество операций:

  • Проверяет наличие изменений, которые не были внесены в системы контроля версий;

  • Проверяет, что нет snapshot зависимостей;

  • Обновляет pom.xml файл в системе контроля версий;

  • Проверяет версию приложения и удаляет snapshot-ы из версии перед релизом;

  • Выполняет тесты;

  • Выполняет фиксацию (commit) изменённого файла pom.xml;

  • Отмечает код в системе контроля версий;

  • Изменяет (т.е. увеличивает) номер версии и “подтягивает” snapshot-ы для будущих релизов;

  • Выполняет фиксацию (commit) изменённых файлов pom.xml в системы контроля версий.

[INFO] Scanning for projects...
[INFO]
[INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] Building maven-release-plugin-example 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-release-plugin:2.5.3:prepare (default-cli) @ maven-release-plugin-example ---
[INFO] Verifying that there are no local modifications...
[INFO]   ignoring changes on: **/pom.xml.releaseBackup, **/pom.xml.next, **/pom.xml.tag, **/pom.xml.branch, **/release.properties, **/pom.xml.backup
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git rev-parse --show-toplevel
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git status --porcelain .
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[WARNING] Ignoring unrecognized line: ?? release.properties
[INFO] Checking dependencies and plugins for snapshots ...
What is the release version for "maven-release-plugin-example"? (by.rakovets.example:maven-release-plugin-example) 1.0: :
What is SCM release tag or label for "maven-release-plugin-example"? (by.rakovets.example:maven-release-plugin-example) maven-release-plugin-example-1.0: : v1.0
What is the new development version for "maven-release-plugin-example"? (by.rakovets.example:maven-release-plugin-example) 1.1-SNAPSHOT: :
[INFO] Transforming 'maven-release-plugin-example'...
[INFO] Not generating release POMs
[INFO] Executing goals 'clean verify'...
[WARNING] Maven will be executed in interactive mode, but no input stream has been configured for this MavenInvoker instance.
[INFO] [INFO] Scanning for projects...
[INFO] [INFO]
[INFO] [INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] [INFO] Building maven-release-plugin-example 1.0
[INFO] [INFO] --------------------------------[ jar ]---------------------------------
[INFO] [INFO]
[INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven-release-plugin-example ---
[INFO] [INFO] Deleting /home/rakovets/mavemaven-release-plugin-example/target
[INFO] [INFO]
[INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-release-plugin-example ---
[INFO] [INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] [INFO] skip non existing resourceDirectory /home/rakovets/mavemaven-release-plugin-example/src/main/resources
[INFO] [INFO]
[INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-release-plugin-example ---
[INFO] [INFO] Changes detected - recompiling the module!
[INFO] [INFO] Compiling 1 source file to /home/rakovets/mavemaven-release-plugin-example/target/classes
[INFO] [INFO]
[INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-release-plugin-example ---
[INFO] [INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] [INFO] skip non existing resourceDirectory /home/rakovets/mavemaven-release-plugin-example/src/test/resources
[INFO] [INFO]
[INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ maven-release-plugin-example ---
[INFO] [INFO] No sources to compile
[INFO] [INFO]
[INFO] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ maven-release-plugin-example ---
[INFO] [INFO] No tests to run.
[INFO] [INFO]
[INFO] [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ maven-release-plugin-example ---
[INFO] [INFO] Building jar: /home/rakovets/mavemaven-release-plugin-example/target/maven-release-plugin-example-1.0.jar
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] [INFO] BUILD SUCCESS
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] [INFO] Total time:  0.762 s
[INFO] [INFO] Finished at: 2021-10-21T07:16:34+03:00
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] Checking in modified POMs...
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git add -- pom.xml
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git rev-parse --show-toplevel
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git status --porcelain .
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[WARNING] Ignoring unrecognized line: ?? pom.xml.releaseBackup
[WARNING] Ignoring unrecognized line: ?? release.properties
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git commit --verbose -F /tmp/maven-scm-14803953.commit pom.xml
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git symbolic-ref HEAD
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git push https://github.com/rakovets/maven-release-plugin-example.git refs/heads/master:refs/heads/master
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Tagging release with the label v1.0...
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git tag -F /tmp/maven-scm-1320350749.commit v1.0
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git push https://github.com/rakovets/maven-release-plugin-example.git refs/tags/v1.0
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git ls-files
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Transforming 'maven-release-plugin-example'...
[INFO] Not removing release POMs
[INFO] Checking in modified POMs...
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git add -- pom.xml
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git rev-parse --show-toplevel
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git status --porcelain .
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[WARNING] Ignoring unrecognized line: ?? pom.xml.releaseBackup
[WARNING] Ignoring unrecognized line: ?? release.properties
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git commit --verbose -F /tmp/maven-scm-984134260.commit pom.xml
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git symbolic-ref HEAD
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git push https://github.com/rakovets/maven-release-plugin-example.git refs/heads/master:refs/heads/master
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Release preparation complete.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  22.817 s
[INFO] Finished at: 2021-10-21T07:16:40+03:00
[INFO] ------------------------------------------------------------------------
Project structure
.
├── pom.xml
├── pom.xml.releaseBackup
├── release.properties
├── src
│   └── main
│       └── java
│           └── Application.java
└── target
    ├── classes
    │   └── Application.class
    ├── generated-sources
    │   └── annotations
    ├── maven-archiver
    │   └── pom.properties
    ├── maven-release-plugin-example-1.0.jar
    └── maven-status
        └── maven-compiler-plugin
            └── compile
                └── default-compile
                    ├── createdFiles.lst
                    └── inputFiles.lst
git log --oneline
04dd7e1 (HEAD -> master) [maven-release-plugin]-prepare for next development iteration
7e96d1e (tag: v1.0) [maven-release-plugin]-prepare release v1.0
fff3392 (origin/master, origin/HEAD) feat: init project
git fetch + git log --oneline
04dd7e1 (HEAD -> master, origin/master, origin/HEAD) [maven-release-plugin]-prepare for next development iteration
7e96d1e (tag: v1.0) [maven-release-plugin]-prepare release v1.0
fff3392 feat: init project
git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	pom.xml.releaseBackup
	release.properties

nothing added to commit but untracked files present (use "git add" to track)

14.3.2. release:perform

mvn release:perform

Проверяет код, используя предыдущую метку и запускает goaldeploy – для развертывания артефакта, полученного в результате сборки в remote repository.

Если подготовка релиза не была произведена, то выведет:

Output
[INFO] Scanning for projects...
[INFO]
[INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] Building maven-release-plugin-example 1.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-release-plugin:2.5.3:perform (default-cli) @ maven-release-plugin-example ---
[ERROR] No SCM URL was provided to perform the release from
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.380 s
[INFO] Finished at: 2021-10-21T07:42:28+03:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-release-plugin:2.5.3:perform (default-cli) on project maven-release-plugin-example: No SCM URL was provided to perform the release from -> [Help 1]
[ERROR]
[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.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
rakovets@ubuntu:/home/rakovets/mavemaven-release-plugin-example$

Если подготовка проекта была успешно завершена, то выполняется загрузка артефакта в remote repository.

[INFO] Scanning for projects...
[INFO]
[INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] Building maven-release-plugin-example 1.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-release-plugin:2.5.3:perform (default-cli) @ maven-release-plugin-example ---
[INFO] Checking out the project to perform the release ...
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example/target && git clone --branch v1.0 https://github.com/rakovets/maven-release-plugin-example.git /home/rakovets/mavemaven-release-plugin-example/target/checkout
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example/target
[INFO] Executing: /bin/sh -c cd /tmp && git ls-remote https://github.com/rakovets/maven-release-plugin-example.git
[INFO] Working directory: /tmp
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example/target/checkout && git fetch https://github.com/rakovets/maven-release-plugin-example.git
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example/target/checkout
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example/target/checkout && git checkout v1.0
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example/target/checkout
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example/target/checkout && git ls-files
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example/target/checkout
[INFO] Invoking perform goals in directory /home/rakovets/mavemaven-release-plugin-example/target/checkout
[INFO] Executing goals 'deploy'...
[WARNING] Maven will be executed in interactive mode, but no input stream has been configured for this MavenInvoker instance.
[INFO] [INFO] Scanning for projects...
[INFO] [INFO]
[INFO] [INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] [INFO] Building maven-release-plugin-example 1.0
[INFO] [INFO] --------------------------------[ jar ]---------------------------------
[INFO] [INFO]
[INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-release-plugin-example ---
[INFO] [INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] [INFO] skip non existing resourceDirectory /home/rakovets/mavemaven-release-plugin-example/target/checkout/src/main/resources
[INFO] [INFO]
[INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-release-plugin-example ---
[INFO] [INFO] Changes detected - recompiling the module!
[INFO] [INFO] Compiling 1 source file to /home/rakovets/mavemaven-release-plugin-example/target/checkout/target/classes
[INFO] [INFO]
[INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ maven-release-plugin-example ---
[INFO] [INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] [INFO] skip non existing resourceDirectory /home/rakovets/mavemaven-release-plugin-example/target/checkout/src/test/resources
[INFO] [INFO]
[INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ maven-release-plugin-example ---
[INFO] [INFO] No sources to compile
[INFO] [INFO]
[INFO] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ maven-release-plugin-example ---
[INFO] [INFO] No tests to run.
[INFO] [INFO]
[INFO] [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ maven-release-plugin-example ---
[INFO] [INFO] Building jar: /home/rakovets/mavemaven-release-plugin-example/target/checkout/target/maven-release-plugin-example-1.0.jar
[INFO] [INFO]
[INFO] [INFO] --- maven-install-plugin:2.4:install (default-install) @ maven-release-plugin-example ---
[INFO] [INFO] Installing /home/rakovets/mavemaven-release-plugin-example/target/checkout/target/maven-release-plugin-example-1.0.jar to /home/rakovets/.m2/repository/by/rakovets/example/maven-release-plugin-example/1.0/maven-release-plugin-example-1.0.jar
[INFO] [INFO] Installing /home/rakovets/mavemaven-release-plugin-example/target/checkout/pom.xml to /home/rakovets/.m2/repository/by/rakovets/example/maven-release-plugin-example/1.0/maven-release-plugin-example-1.0.pom
[INFO] [INFO]
[INFO] [INFO] --- maven-deploy-plugin:2.7:deploy (default-deploy) @ maven-release-plugin-example ---
[INFO] Uploading to github: https://maven.pkg.github.com/rakovets/maven-release-plugin-example/by/rakovets/example/maven-release-plugin-example/1.0/maven-release-plugin-example-1.0.jar
[INFO] Progress (1): 2.4 kB
[INFO]
[INFO] Uploaded to github: https://maven.pkg.github.com/rakovets/maven-release-plugin-example/by/rakovets/example/maven-release-plugin-example/1.0/maven-release-plugin-example-1.0.jar (2.4 kB at 632 B/s)
[INFO] Uploading to github: https://maven.pkg.github.com/rakovets/maven-release-plugin-example/by/rakovets/example/maven-release-plugin-example/1.0/maven-release-plugin-example-1.0.pom
[INFO] Progress (1): 1.6 kB
[INFO]
[INFO] Uploaded to github: https://maven.pkg.github.com/rakovets/maven-release-plugin-example/by/rakovets/example/maven-release-plugin-example/1.0/maven-release-plugin-example-1.0.pom (1.6 kB at 447 B/s)
[INFO] Downloading from github: https://maven.pkg.github.com/rakovets/maven-release-plugin-example/by/rakovets/example/maven-release-plugin-example/maven-metadata.xml
[INFO] Progress (1): 241 B
[INFO]
[INFO] Downloaded from github: https://maven.pkg.github.com/rakovets/maven-release-plugin-example/by/rakovets/example/maven-release-plugin-example/maven-metadata.xml (241 B at 344 B/s)
[INFO] Uploading to github: https://maven.pkg.github.com/rakovets/maven-release-plugin-example/by/rakovets/example/maven-release-plugin-example/maven-metadata.xml
[INFO] Progress (1): 348 B
[INFO]
[INFO] Uploaded to github: https://maven.pkg.github.com/rakovets/maven-release-plugin-example/by/rakovets/example/maven-release-plugin-example/maven-metadata.xml (348 B at 451 B/s)
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] [INFO] BUILD SUCCESS
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] [INFO] Total time:  9.873 s
[INFO] [INFO] Finished at: 2021-10-21T07:21:51+03:00
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] Cleaning up after release...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  16.730 s
[INFO] Finished at: 2021-10-21T07:21:51+03:00
[INFO] ------------------------------------------------------------------------
git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

14.3.3. release:clean

Для демонстрации, специально допускаем compile error и делает commit:

src/main/java/Application.java
public class Application {
    public static void main(String[] args) {
        System.out.println("Hello maven-release-plugin");
    }
git log --oneline
78793ca (HEAD -> master) feat: add compile error
04dd7e1 (origin/master, origin/HEAD) [maven-release-plugin]-prepare for next development iteration
7e96d1e (tag: v1.0) [maven-release-plugin]-prepare release v1.0
fff3392 feat: init project

Подготавливаем релиз:

mvn release:prepare
Output
[INFO] Scanning for projects...
[INFO]
[INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] Building maven-release-plugin-example 1.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-release-plugin:2.5.3:prepare (default-cli) @ maven-release-plugin-example ---
[INFO] Resuming release from phase 'scm-check-modifications'
[INFO] Verifying that there are no local modifications...
[INFO]   ignoring changes on: **/pom.xml.releaseBackup, **/pom.xml.next, **/pom.xml.tag, **/pom.xml.branch, **/release.properties, **/pom.xml.backup
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git rev-parse --show-toplevel
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git status --porcelain .
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[WARNING] Ignoring unrecognized line: ?? release.properties
[INFO] Checking dependencies and plugins for snapshots ...
What is the release version for "maven-release-plugin-example"? (by.rakovets.example:maven-release-plugin-example) 1.1: :
What is SCM release tag or label for "maven-release-plugin-example"? (by.rakovets.example:maven-release-plugin-example) maven-release-plugin-example-1.1: : v1.1
What is the new development version for "maven-release-plugin-example"? (by.rakovets.example:maven-release-plugin-example) 1.2-SNAPSHOT: :
[INFO] Transforming 'maven-release-plugin-example'...
[INFO] Not generating release POMs
[INFO] Executing goals 'clean verify'...
[WARNING] Maven will be executed in interactive mode, but no input stream has been configured for this MavenInvoker instance.
[INFO] [INFO] Scanning for projects...
[INFO] [INFO]
[INFO] [INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] [INFO] Building maven-release-plugin-example 1.1
[INFO] [INFO] --------------------------------[ jar ]---------------------------------
[INFO] [INFO]
[INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven-release-plugin-example ---
[INFO] [INFO] Deleting /home/rakovets/mavemaven-release-plugin-example/target
[INFO] [INFO]
[INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-release-plugin-example ---
[INFO] [INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] [INFO] skip non existing resourceDirectory /home/rakovets/mavemaven-release-plugin-example/src/main/resources
[INFO] [INFO]
[INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-release-plugin-example ---
[INFO] [INFO] Changes detected - recompiling the module!
[INFO] [INFO] Compiling 1 source file to /home/rakovets/mavemaven-release-plugin-example/target/classes
[INFO] [INFO] -------------------------------------------------------------
[INFO] [ERROR] COMPILATION ERROR :
[INFO] [INFO] -------------------------------------------------------------
[INFO] [ERROR] /home/rakovets/mavemaven-release-plugin-example/src/main/java/Application.java:[4,6] reached end of file while parsing
[INFO] [INFO] 1 error
[INFO] [INFO] -------------------------------------------------------------
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] [INFO] BUILD FAILURE
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] [INFO] Total time:  0.552 s
[INFO] [INFO] Finished at: 2021-10-21T07:31:07+03:00
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project maven-release-plugin-example: Compilation failure
[INFO] [ERROR] /home/rakovets/mavemaven-release-plugin-example/src/main/java/Application.java:[4,6] reached end of file while parsing
[INFO] [ERROR]
[INFO] [ERROR] -> [Help 1]
[INFO] [ERROR]
[INFO] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[INFO] [ERROR] Re-run Maven using the -X switch to enable full debug logging.
[INFO] [ERROR]
[INFO] [ERROR] For more information about the errors and possible solutions, please read the following articles:
[INFO] [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  9.658 s
[INFO] Finished at: 2021-10-21T07:31:07+03:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-release-plugin:2.5.3:prepare (default-cli) on project maven-release-plugin-example: Maven execution failed, exit code: '1' -> [Help 1]
[ERROR]
[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.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
Project structure
.
├── pom.xml
├── pom.xml.releaseBackup
├── release.properties
├── src
│   └── main
│       └── java
│           └── Application.java
└── target
    ├── classes
    ├── generated-sources
    │   └── annotations
    └── maven-status
        └── maven-compiler-plugin
            └── compile
                └── default-compile
                    ├── createdFiles.lst
                    └── inputFiles.lst

Выполняет очистку в случае, если релиз не был успешным.

mvn release:clean
Output
[INFO] Scanning for projects...
[INFO]
[INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] Building maven-release-plugin-example 1.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-release-plugin:2.5.3:clean (default-cli) @ maven-release-plugin-example ---
[INFO] Cleaning up after release...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.377 s
[INFO] Finished at: 2021-10-21T07:32:49+03:00
[INFO] ------------------------------------------------------------------------
Project structure
.
├── pom.xml
├── src
│   └── main
│       └── java
│           └── Application.java
└── target
    ├── classes
    ├── generated-sources
    │   └── annotations
    └── maven-status
        └── maven-compiler-plugin
            └── compile
                └── default-compile
                    ├── createdFiles.lst
                    └── inputFiles.lst
git log --oneline
78793ca (HEAD -> master) feat: add compile error
04dd7e1 (origin/master, origin/HEAD) [maven-release-plugin]-prepare for next development iteration
7e96d1e (tag: v1.0) [maven-release-plugin]-prepare release v1.0
fff3392 feat: init project
git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   pom.xml

no changes added to commit (use "git add" and/or "git commit -a")

14.3.4. release:rollback

Для демонстрации, специально допускаем compile error и делает commit:

src/main/java/Application.java
public class Application {
    public static void main(String[] args) {
        System.out.println("Hello maven-release-plugin");
    }
git log --oneline
78793ca (HEAD -> master) feat: add compile error
04dd7e1 (origin/master, origin/HEAD) [maven-release-plugin]-prepare for next development iteration
7e96d1e (tag: v1.0) [maven-release-plugin]-prepare release v1.0
fff3392 feat: init project

Подготавливаем релиз:

mvn release:prepare
Output
[INFO] Scanning for projects...
[INFO]
[INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] Building maven-release-plugin-example 1.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-release-plugin:2.5.3:prepare (default-cli) @ maven-release-plugin-example ---
[INFO] Verifying that there are no local modifications...
[INFO]   ignoring changes on: **/pom.xml.releaseBackup, **/pom.xml.next, **/pom.xml.tag, **/pom.xml.branch, **/release.properties, **/pom.xml.backup
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git rev-parse --show-toplevel
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git status --porcelain .
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[WARNING] Ignoring unrecognized line: ?? release.properties
[INFO] Checking dependencies and plugins for snapshots ...
What is the release version for "maven-release-plugin-example"? (by.rakovets.example:maven-release-plugin-example) 1.1: :
What is SCM release tag or label for "maven-release-plugin-example"? (by.rakovets.example:maven-release-plugin-example) maven-release-plugin-example-1.1: : v1.1
What is the new development version for "maven-release-plugin-example"? (by.rakovets.example:maven-release-plugin-example) 1.2-SNAPSHOT: :
[INFO] Transforming 'maven-release-plugin-example'...
[INFO] Not generating release POMs
[INFO] Executing goals 'clean verify'...
[WARNING] Maven will be executed in interactive mode, but no input stream has been configured for this MavenInvoker instance.
[INFO] [INFO] Scanning for projects...
[INFO] [INFO]
[INFO] [INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] [INFO] Building maven-release-plugin-example 1.1
[INFO] [INFO] --------------------------------[ jar ]---------------------------------
[INFO] [INFO]
[INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ maven-release-plugin-example ---
[INFO] [INFO] Deleting /home/rakovets/mavemaven-release-plugin-example/target
[INFO] [INFO]
[INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ maven-release-plugin-example ---
[INFO] [INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] [INFO] skip non existing resourceDirectory /home/rakovets/mavemaven-release-plugin-example/src/main/resources
[INFO] [INFO]
[INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ maven-release-plugin-example ---
[INFO] [INFO] Changes detected - recompiling the module!
[INFO] [INFO] Compiling 1 source file to /home/rakovets/mavemaven-release-plugin-example/target/classes
[INFO] [INFO] -------------------------------------------------------------
[INFO] [ERROR] COMPILATION ERROR :
[INFO] [INFO] -------------------------------------------------------------
[INFO] [ERROR] /home/rakovets/mavemaven-release-plugin-example/src/main/java/Application.java:[4,6] reached end of file while parsing
[INFO] [INFO] 1 error
[INFO] [INFO] -------------------------------------------------------------
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] [INFO] BUILD FAILURE
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] [INFO] Total time:  0.559 s
[INFO] [INFO] Finished at: 2021-10-21T07:38:04+03:00
[INFO] [INFO] ------------------------------------------------------------------------
[INFO] [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project maven-release-plugin-example: Compilation failure
[INFO] [ERROR] /home/rakovets/mavemaven-release-plugin-example/src/main/java/Application.java:[4,6] reached end of file while parsing
[INFO] [ERROR]
[INFO] [ERROR] -> [Help 1]
[INFO] [ERROR]
[INFO] [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[INFO] [ERROR] Re-run Maven using the -X switch to enable full debug logging.
[INFO] [ERROR]
[INFO] [ERROR] For more information about the errors and possible solutions, please read the following articles:
[INFO] [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  10.012 s
[INFO] Finished at: 2021-10-21T07:38:04+03:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-release-plugin:2.5.3:prepare (default-cli) on project maven-release-plugin-example: Maven execution failed, exit code: '1' -> [Help 1]
[ERROR]
[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.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
Project structure
.
├── pom.xml
├── pom.xml.releaseBackup
├── release.properties
├── src
│   └── main
│       └── java
│           └── Application.java
└── target
    ├── classes
    ├── generated-sources
    │   └── annotations
    └── maven-status
        └── maven-compiler-plugin
            └── compile
                └── default-compile
                    ├── createdFiles.lst
                    └── inputFiles.lst

Откатывает изменения, которые были сделаны в коде и конфигурациях, если последний релиз не был успешным.

mvn release:rollback
Output
[INFO] Scanning for projects...
[INFO]
[INFO] ----------< by.rakovets.example:maven-release-plugin-example >----------
[INFO] Building maven-release-plugin-example 1.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-release-plugin:2.5.3:rollback (default-cli) @ maven-release-plugin-example ---
[INFO] Checking in modified POMs...
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git add -- pom.xml
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git rev-parse --show-toplevel
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[INFO] Executing: /bin/sh -c cd /home/rakovets/mavemaven-release-plugin-example && git status --porcelain .
[INFO] Working directory: /home/rakovets/mavemaven-release-plugin-example
[WARNING] Ignoring unrecognized line: ?? pom.xml.releaseBackup
[WARNING] Ignoring unrecognized line: ?? release.properties
[INFO] Cleaning up after release...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.428 s
[INFO] Finished at: 2021-10-21T07:38:59+03:00
[INFO] ------------------------------------------------------------------------
Project structure
.
├── pom.xml
├── src
│   └── main
│       └── java
│           └── Application.java
└── target
    ├── classes
    ├── generated-sources
    │   └── annotations
    └── maven-status
        └── maven-compiler-plugin
            └── compile
                └── default-compile
                    ├── createdFiles.lst
                    └── inputFiles.lst
git log --oneline
78793ca (HEAD -> master) feat: add compile error
04dd7e1 (origin/master, origin/HEAD) [maven-release-plugin]-prepare for next development iteration
7e96d1e (tag: v1.0) [maven-release-plugin]-prepare release v1.0
fff3392 feat: init project
git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean