Apache Maven

Problem

Problem

All actions MUST be done MANUALLY.

  • create project structure

  • search and download dependencies

  • compile

  • run tests

  • build artifacts (jar, war)

  • deploy to web-server/application server/servlet container

  • etc.

Solution

Solution

Apache Maven logo

Solution

Аll actions CAN be AUTOMATED.

  • generate project structure

  • search and download dependencies

  • compile

  • run tests

  • build artifacts (jar, war)

  • deploy to web-server/application server/servlet container

  • etc.

Install

Install

  • download binary archive (https://maven.apache.org/download.cgi)

  • check environment variable JAVA_HOME with CLI command echo %JAVA_HOME%/echo $JAVA_HOME (*optional)

  • add path for directory bin of Apache Maven to environment variable PATH

  • check installation with CLI command mvn -v

Create new project

Create new project

  • Запустите терминал (PowerShell в windows)

  • Запустите следующую CLI команду: mvn archetype:generate

    • При первом запуске: будет отображен статус скачивания

    • При последующих запусках: будет отображен список archetypes

  • Выбираем archetype по умолчанию (с именем maven-archetype-quickstart)

  • Вводим/выбираем необходимые значения для проекта

  • Смотрим структуру проекта

Archetype generate: output

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 1637:
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
Define value for property 'artifactId': apache-maven
Define value for property 'version' 1.0-SNAPSHOT: :
Define value for property 'package' by.rakovets: :
Confirm properties configuration:
groupId: by.rakovets
artifactId: apache-maven
version: 1.0-SNAPSHOT
package: by.rakovets
 Y: : y

Archetype generate

  • groupId - иерархического расположения проекта в Maven-repository (чаще всего: reverse domain name + department + project, например: by.rakovets.ems)

  • artifactId - идентификатор проекта/подпроекта (например: ems-api-users)

  • version - версия проекта (по умолчанию: 1.0-SNAPSHOT)

Project structure

$ tree apache-maven/
apache-maven/
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── com
    │           └── rakovets
    │               └── App.java
    └── test
        └── java
            └── com
                └── rakovets
                    └── AppTest.java

9 directories, 3 files

Apache Maven Concept

pom.xml

  • POMProject Object Model

  • Основной конфигурационный файл для Maven-приложения или модуля

  • Содержит настройки:

    • общие для проекта

    • зависимостей

    • плагинов

    • профилей

    • и т.д.

Project Object Model (POM)

POM

Project Object Model (POM)

<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>

    <!-- Basic -->
    <groupId>...</groupId>
    <artifactId>...</artifactId>
    <version>...</version>
    <packaging>...</packaging>
    <dependencies>...</dependencies>
    <parent>...</parent>
    <dependencyManagement>...</dependencyManagement>
    <modules>...</modules>
    <properties>...</properties>

    <!-- Setting for build/reporting -->
    <build>...</build>
    <reporting>...</reporting>

    <!-- Metadata for project -->
    <name>....</name>
    <description>...</description>
    <organization>...</organization>

    <!-- Development environment -->
    <repositories>...</repositories>
    <pluginRepositories>...</pluginRepositories>
    <profiles>...</profiles>
</project>

Apache Maven Concept

  • Phases

  • Plugins and Goals

  • Artifacts

  • Repositories

Apache Maven Concept

  • Dependencies

    • Dependency

    • Parent

    • Module

  • Profiles

  • Properties

Lifecycle

Maven Flow

Apache Maven Flow

Build Life Cycles

Maven provides three build-in build life cycles:

  • default - project deployment (mvn)

  • clean - project cleaning (mvn clean)

  • site - site documentation (mvn site)

Build Phases

The default-lifecycle executes the following build phases:

  • validate - validates the consistency of the project

  • compile - compiles the source code

  • test - runs the (local) tests

  • package - packages the compiled and tested code

  • verify - runs integration tests on the packaged software

  • install - pushes the package to the local Maven repository

  • deploy - deploys the final package to the remote repository

Lifecycle

Apache Maven Lifecycle

Full lifecycle

Plugins

Plugin

  • Plugin - дополнение Apache Maven.

  • Позволяет расширить его функциональные возможности.

  • Позволяет произвести конфигурацию отдельных этапов жизненного цикла.

Plugins

plugins

Example: maven-compiler-plugin

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
</plugin>

Artifact

Artifacts

Artifacts

Artifacts

  • jar

  • war

  • ear

  • pom

Repository

Repository

Repository

Repositories

Dependencies

???

Scope

maven-dependency-plugin

maven-dependency-plugin

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <configuration>
        <outputDirectory>
            ${project.build.directory}/lib/
        </outputDirectory>
        <overWriteReleases>false</overWriteReleases>
        <overWriteSnapshots>false</overWriteSnapshots>
        <overWriteIfNewer>true</overWriteIfNewer>
    </configuration>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
        </execution>
    </executions>
</plugin>

maven-dependency-plugin options

  • outputDirectory - определение директории, в которую будут копироваться зависимости

  • overWriteReleases - флаг необходимости перезаписывания зависимостей при создании RELEASE (default: false)

  • overWriteSnapshots - флаг необходимости перезаписывания неокончательных зависимостей, в которых присутствует SNAPSHOT (default: false)

  • overWriteIfNewer - флаг необходимости перезаписывания библиотек с наличием более новых версий (default: true)

maven-dependency-plugin goals

  • mvn dependency:tree - вывод на экран дерева зависимостей

  • mvn dependency:analyze - анализ зависимостей (используемые, неиспользуемые, указанные, неуказанные)

  • mvn dependency:copy-dependencies - копирует зависимости

maven-dependency-plugin goals

  • mvn dependency:analyze-duplicate - определение дублирующиеся зависимостей

  • mvn dependency:resolve - разрешение (определение) всех зависимостей

  • mvn dependency:resolve-plugin - разрешение (определение) всех плагинов

Property

Type properties

  • объявленные внутри pom.xml

  • предопределённые переменные.

  • объявленные во внешнем файле

Переменные объявленные внутри pom.xml

<project>
    ...
    <properties>
        <temp.directory>/tmp</temp.directory>
        <jetty.version>6.1.25</jetty.version>
    </properties>

    <dependency>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty</artifactId>
        <version>${jetty.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-util</artifactId>
        <version>${jetty.version}</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-management</artifactId>
        <version>${jetty.version}</version>
        <scope>provided</scope>
    </dependency>

    <build>
        <outputDirectory>${temp.directory}</outputDirectory>
    </build>
    ...
</project>

Предопределённые переменные

Предопределённые переменные можно разделить на несколько видов.

  • Встроенные свойства:

    • ${basedir} - путь к директории с pom.xml

    • ${version}/${project.version}/${pom.version} - версия artifact

Предопределённые переменные

  • Свойства проекта:

    • ${project.build.directory}/${pom.project.build.directory} - путь к директории для сборки (default: target)

    • ${project.build.outputDirectory} - путь к директории для скомпилированых классов, (default: target/classes)

    • ${project.name}/${pom.name} - имя проекта

    • ${project.version}/${pom.version} - версия проекта

Предопределённые переменные

  • Настройки пользователя (из ~/.m2/settings.xml):

    • ${settings.localRepository} путь к локальному репозиторию пользователя

  • Переменные окружения:

    • ${env.M2_HOME}

    • ${java.home}

Предопределённые переменные

  • Системные свойства System.properties

    • Доступ к системным свойствам возможен напрямую. Для просмотра переменных можно воспользоваться maven-echo-plugin.

Переменные объявленные во внешнем файле

<project>
    ...
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>maven-properties-plugin</artifactId>
        <version>1.0-SNAPSHOT</version>
        <executions>
            <execution>
                <phase>initialize</phase>
                <goals>
                    <goal>read-project-properties</goal>
                </goals>
                <configuration>
                    <files>
                        <file>src/config/app.properties</file>
                    </files>
                </configuration>
            </execution>
        </executions>
    </plugin>
    ...
</project>

Install custom library

Install custom library

mvn install:install-file \
    -Dfile=mariadb-java-client-2.6.1.jar \
    -DgroupId=org.mariadb \
    -DartifactId=mariadb-java-client \
    -Dversion=2.6.1 \
    -Dpackaging=jar \
    -DgeneratePom=true

Install custom library

<dependency>
    <groupId>org.mariadb</groupId>
    <artifactId>mariadb-java-client</artifactId>
    <version>2.6.1</version>
</dependency>

Multi-modules

Multi-Module

<project>
    ...
    <modules>
        <module>project1</module>
        <module>project2</module>
        ...
    </modules>
    ...
</project>

Inheritance (Parent POM)

<project>
    <groupId>by.rakovets</groupId>
    <artifactId>project</artifactId>
    <version>0.0.1</version>
    <packaging>pom</packaging>
    ...
    <modules>
        <module>project1</module>
        <module>project2</module>
        ...
    </modules>
    ...
</project>

Inheritance (Child POM)

<project>
    <groupId>by.rakovets</groupId>
    <artifactId>project1</artifactId>
    <version>0.0.1</version>
    <packaging>jar</packaging>
    ...
    <parent>
        <groupId>by.rakovets</groupId>
        <artifactId>project</artifactId>
        <version>0.0.1</version>
    </parent>
    ...
</project>

Enable Dependency Management in Parent Project

<project>
    ...
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-api</artifactId>
                <version>5.6.2</version>
                <scope>test</scope>
            </dependency>
            ...
        </dependencies>
    </dependencyManagement>
    ...
</project>

Use Dependency in Submodules

<project>
    ...
    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
        </dependency>
        ...
    </dependencies>
    ...
</project>

Profiles

Profile

Profile - это настройки, описанные в pom.xml, которые могут быть запущены когда необходимо.

Способы запуска profiles

  • CLI

  • ~/.m2/settings.xml

  • system property

Profile with CLI

<project>
    ...
    <profiles>
        <profile>
            <id>dev</id>
            ...
        </profile>
    </profiles>
</project>

Profile with CLI

mvn test -P dev

Profile with ~/.m2/settings.xml

<settings>
    ...
    <activeProfiles>
        <activeProfile>test</activeProfile>
    </activeProfiles>
    ...
</settings>

Profile with ~/.m2/settings.xml

mvn test

Profile with system property

<project>
    ...
    <profiles>
        <profile>
            <activation>
                <property>
                    <name>environment</name>
                    <value>dev</value>
                </property>
            </activation>
            ...
        </profile>
        ...
    </profiles>
</project>

Profile with system property

mvn test -Denvironment=dev

Releases

???

Deploy

Deploy to Container

Cargo Maven Plugin

<dependency>
    <groupId>org.codehaus.cargo</groupId>
    <artifactId>cargo-maven3-plugin</artifactId>
    <version>1.9.9</version>
</dependency>

Local deploy

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.cargo</groupId>
            <artifactId>cargo-maven3-plugin</artifactId>
            <version>1.9.0</version>
            <executions>
                <execution>
                    <phase>install</phase>
                    <goals>
                        <goal>deploy</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <container>
                    <containerId>tomcat10x</containerId>
                    <type>installed</type>
                    <home>/opt/apache-tomcat/10.0.14</home>
                </container>
                <configuration>
                    <type>existing</type>
                    <home>/opt/apache-tomcat/10.0.14</home>
                </configuration>
            </configuration>
        </plugin>
    </plugins>
</build>

Remote deploy

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.cargo</groupId>
            <artifactId>cargo-maven3-plugin</artifactId>
            <version>1.9.0</version>
            <executions>
                <execution>
                    <phase>install</phase>
                    <goals>
                        <goal>deploy</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
            <container>
                <containerId>tomcat8x</containerId>
                <type>remote</type>
            </container>
            <configuration>
                <type>runtime</type>
                <properties>
                    <cargo.remote.username>admin</cargo.remote.username>
                    <cargo.remote.password>admin</cargo.remote.password>
                    <cargo.tomcat.manager.url>http://localhost:8080/manager</cargo.tomcat.manager.url>
                </properties>
            </configuration>
        </configuration>
        </plugin>
    </plugins>
</build>