W3docs

Java Maven pom.xml

Структура Maven pom.xml: координаты GAV, зависимости, свойства и наследование через родительский POM.

pom.xml — это сердце любого Maven-проекта. POM расшифровывается как Project Object Model — единый XML-файл, который объявляет что представляет собой ваш проект (его идентификация), что ему нужно (зависимости) и как его собрать (плагины и конфигурация). Maven читает этот файл, скачивает всё, на что он ссылается, из репозитория и запускает сборку. Там, где стихийный проект разбрасывает эти сведения по shell-скриптам и папке lib/ с вручную скопированными JAR-файлами, Maven собирает всё в один декларативный, версионируемый документ.

Эта глава разбирает структуру POM по частям: минимальный скелет, координаты GAV, именующие каждый артефакт, принцип работы зависимостей и областей видимости (scope), свойства для устранения дублирования версий и наследование через родительский POM. Если вы только начинаете изучать Maven, начните с введения в Maven; для понимания фаз сборки, управляемых POM, смотрите раздел жизненного цикла сборки Maven.

Минимальный POM

Каждый POM — это XML-документ с корневым элементом <project>, соответствующим схеме Maven 4.0.0. Наименьший работоспособный 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>

  <groupId>com.w3docs</groupId>
  <artifactId>shop-api</artifactId>
  <version>1.4.0</version>
  <packaging>jar</packaging>
</project>

<modelVersion> всегда равен 4.0.0 — это версия формата POM, а не вашего кода. Оставьте его именно таким.

Координаты: groupId, artifactId, version

Maven-артефакт идентифицируется своими GAV-координатами. Каждая зависимость, которую вы когда-либо добавите, именуется теми же тремя (иногда четырьмя) значениями, поэтому стоит изучить их точно:

ЭлементЗначениеСоглашение
groupIdОрганизация или пространство имёнОбратный DNS, например com.google.code.gson
artifactIdИмя проекта внутри группыСтрочные буквы, через дефис, например shop-api
versionВыпуск данного артефактаСемантическое, например 1.4.0; -SNAPSHOT для незавершённых сборок
packagingТип выходного файлаjar (по умолчанию), war, pom

Вместе groupId:artifactId:version глобально уникальны. Именно это Maven использует для поиска JAR в репозитории и именования артефакта, который создаёт ваша сборка. Версия, оканчивающаяся на -SNAPSHOT (например, 1.5.0-SNAPSHOT), — это изменяемая сборка в разработке, которую Maven может перекачать; обычная версия считается неизменяемой.

Объявление зависимостей

Зависимости перечисляются в элементе <dependencies>, каждая в виде блока <dependency> с координатами нужной библиотеки. Maven разрешает их — а также их зависимости, транзитивно — из репозитория (по умолчанию Maven Central):

<dependencies>
  <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.11.0</version>
  </dependency>
  <dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.2</version>
    <scope>test</scope>
  </dependency>
</dependencies>

Элемент <scope> управляет тем, когда зависимость находится в classpath. compile (по умолчанию) означает везде; test — только при компиляции и запуске тестов, так что JUnit никогда не попадёт внутрь вашего JAR. Другие области видимости включают provided (предоставляется средой выполнения, например, servlet API) и runtime (нужна для запуска, но не для компиляции, например, JDBC-драйвер). Транзитивное разрешение, конфликты версий и правила областей видимости подробно рассматриваются в разделе зависимости Maven.

Свойства: не повторяйте версии

Элемент <properties> определяет переиспользуемые переменные, на которые ссылаются в других местах с синтаксисом ${name}. Идиома состоит в том, чтобы однажды закрепить версию каждой библиотеки наверху, чтобы обновления происходили в одном месте:

<properties>
  <maven.compiler.release>21</maven.compiler.release>
  <junit.version>5.10.2</junit.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
  </dependency>
</dependencies>

maven.compiler.release — это широко известное свойство, которое указывает плагину компилятора, на какую версию Java ориентироваться — это чище, чем настраивать плагин вручную. Когда Maven читает POM, он интерполирует каждый заполнитель ${...}, подставляя значение свойства до разрешения чего-либо.

Наследование через родительский POM

POM образуют иерархию. Элемент <parent> заставляет проект наследовать координаты, свойства и управление зависимостями из другого POM. Стартовый родитель Spring Boot — классический пример: он фиксирует согласованный набор версий библиотек, так что вы можете опустить <version> у управляемых зависимостей:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.3.2</version>
</parent>

<dependencies>
  <dependency>
    <!-- version omitted: inherited from the parent's dependencyManagement -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
</dependencies>

Многомодульная сборка использует тот же механизм в обратном направлении: один агрегирующий POM с <packaging>pom</packaging> перечисляет <modules>, а каждый дочерний называет его как <parent>. Общая конфигурация хранится в одном месте; дочерние POM остаются компактными.

Практический пример: чтение POM так, как это делает Maven

pom.xml — это просто XML, поэтому мы можем разобрать его встроенным DOM API JDK и обойти его структуру точно так же, как Maven, — читая координаты, свойства и каждую зависимость, попутно вручную интерполируя заполнитель ${...}. (Сам Maven — это инструмент сборки, а не библиотека в classpath, но этот пример показывает модель, на которой он работает.)

java— editable, runs on the server

Что можно вынести из запуска:

  • modelVersion выводится как 4.0.0 — константа, которую несёт каждый POM. Она идентифицирует формат POM, а не ваш проект; Maven отверг бы POM, в котором она отсутствует.
  • Координаты выводятся как com.w3docs:shop-api:1.4.0 — тройка GAV в каноническом виде groupId:artifactId:version. Именно эта строка используется Maven для именования артефакта, который создаёт сборка, и каждой зависимости, которую она разрешает.
  • packaging прочитан как jar — тип выходного файла по умолчанию. Если бы было значение pom, это был бы агрегирующий/родительский проект, не производящий собственного JAR.
  • Свойство junit.version разрешено в 5.10.2, а заполнитель ${junit.version} в зависимости JUnit интерполирован в то же самое значение — именно такая подстановка выполняется Maven, чтобы версия объявлялась в одном месте и переиспользовалась.
  • Обход зависимостей сообщил о двух зависимостях и вывел каждую с её областью видимости: Gson принял значение по умолчанию compile (нет элемента <scope>, поэтому она присутствует в каждом classpath), тогда как JUnit показал scope=test, не попадая в поставляемый артефакт.

Практика

Практика
Какова цель трёх элементов groupId, artifactId и version в pom.xml вместе взятых?
Какова цель трёх элементов groupId, artifactId и version в pom.xml вместе взятых?
Was this page helpful?