【Maven 基礎編】Mavenの基本:POM.xmlの全体像:GAV、依存関係からビルド設定まで徹底解説

「Mavenを使っているが、POM.xmlの中身はよく分からない」「プロジェクトのフォルダ構成が複雑で、どこに何があるのか把握しきれない」

このような疑問や悩みを抱えている開発者もいるかもしれません。

Java開発において、Mavenは広く使われているビルドツールです。
しかし、その中心的な設定ファイルであるpom.xmlや、標準的なプロジェクト構造について、深く理解する機会は少ないかもしれません。

本記事では、Mavenプロジェクトの基本的な仕組みについて解説します。

pom.xmlの各要素が持つ意味、標準ディレクトリ構造の役割、そしてそれらがプロジェクトのビルドや管理にどう関わっているのかを、初心者向けに分かりやすく説明します。

この記事を通して、pom.xmlがプロジェクトを管理するための重要なファイルであることを理解し、より効果的に使えるようになることを目指します。

それでは、Mavenの基本的な使い方を見ていきましょう!


対象読者

  • Mavenを使い始めたばかりのJava開発者
  • pom.xmlに何が書かれているのか、基本的な構造を理解したい方
  • Mavenの標準的なプロジェクト構成やビルドライフサイクルについて学びたい方

本記事の目次

  1. Mavenプロジェクトの標準ディレクトリ構造を理解する
  2. 主要な要素:親POM (<parent>) とは?
    • 親POMの内容を確認する方法
  3. プロジェクトの座標:GAVと成果物(アーティファクト)の形式
    • GAV:Mavenの世界における「座標」
    • <packaging>:成果物(アーティファクト)の形式を定義する
  4. 依存関係の定義:<dependencies><dependency>
    • 依存関係のスコープ (<scope>)
  5. ビルド設定:<build>とMavenライフサイクル
    • 3つの標準ライフサイクルとフェーズ、プラグイン
  6. プロパティの活用:<properties>で設定を集中管理する
    • プロパティの種類と使い方
  7. まとめ

1. Mavenプロジェクトの標準ディレクトリ構造を理解する

Mavenは「設定より規約(Convention over Configuration)」という思想を重視しており、標準的なディレクトリ構造が定められています。この規約に従うことで、開発者は面倒なビルド設定から解放されます。

Mavenの標準的なディレクトリ構造:

my-maven-project/
├── .mvn/
   └── wrapper/
       ├── maven-wrapper.jar
       └── maven-wrapper.properties
├── mvnw
├── mvnw.cmd
├── pom.xml
├── .gitignore
└── src/
    ├── main/
       ├── java/        # Javaのソースコード
       └── resources/   # リソースファイル(設定ファイルなど)
    └── test/
        ├── java/        # テストコード
        └── resources/   # テスト用のリソースファイル
└── target/              # ビルド成果物(アーティファクト)(コンパイル済みクラス、JAR/WARなど)
  • mvnw, mvnw.cmd, .mvn/:
    • これらはMaven Wrapperのファイル群です。プロジェクトで使うMavenのバージョンを固定し、開発者全員が同じ環境でビルドできるようにします。
  • pom.xml:
    • プロジェクトオブジェクトモデル(Project Object Model)。プロジェクトの全ての設定情報が記述されています。Mavenの心臓部です。
  • src/main/java:
    • アプリケーションのJavaソースコードを配置します。
  • src/main/resources:
    • アプリケーションが実行時に必要とする設定ファイル(application.propertiesなど)や、SQLファイルなどを配置します。
  • src/test/java:
    • 単体テストや結合テストのJavaソースコードを配置します。
  • src/test/resources:
    • テスト時にのみ必要となるリソースファイル(テスト用のDB設定ファイルなど)を配置します。
  • target/:
    • ./mvnw package などのコマンドを実行した際に、Mavenが生成する全ての成果物(アーティファクト)(コンパイル済みクラスファイル、JAR/WARファイル、レポートなど)が格納されます。

ITアーキテクトの視点:なぜtargetディレクトリをGit管理しないのか?

targetディレクトリは、ソースコードから自動生成されるものだからです。バージョン管理システム(Gitなど)で管理すべきなのは、人間が作成・編集する「ソース(源泉)」だけです。

もしtargetディレクトリをGitにコミットしてしまうと、

  • リポジトリの肥大化: ビルドのたびに大量のファイルが追加され、リポジトリが不必要に大きくなります。
  • 無意味なコンフリクト: チームメンバーがそれぞれビルドした結果が異なると、マージの際に必ずコンフリクト(競合)が発生します。

このような理由から、.gitignoreファイルにtarget/と記述して、Gitの管理対象から除外するのが一般的です。


2. 主要な要素:親POM (<parent>) とは?

Spring Bootプロジェクトのpom.xmlを見ると、ほぼ必ず最初に<parent>という要素が登場します。

これはMavenの「継承」の仕組みを利用して、プロジェクト全体の基本設定を一元管理するためのものです。

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.0.1</version>
    <relativePath/> <!-- 空タグの場合、Mavenはまず相対パス(例:../pom.xml)を探し、見つからなければローカル/リモートリポジトリを探索するデフォルトの挙動を示す -->
</parent>

この継承関係を図で示すと、以下のようになります。spring-boot-starter-parentが、さらにspring-boot-dependenciesというBOM(Bill of Materials)をインポートすることで、多段階の継承構造が実現されている点がポイントです。

POMの継承とインポートの流れ

このspring-boot-starter-parentは、Spring Bootプロジェクトにおける設定の土台となるPOMです。これを親として指定することで、自身のpom.xmlには以下のメリットがあります。

  1. 依存関係のバージョン管理の集約:
    実は、spring-boot-starter-parent自体が、さらにspring-boot-dependenciesという特別なPOMをインポートしています。
    このspring-boot-dependenciesに、Spring Bootが推奨する多数のライブラリ(Spring関連、Jackson、Logbackなど)のバージョンが<dependencyManagement>タグで網羅的に定義されています。
    この仕組みにより、開発者は互換性を考慮したライブラリのバージョンを自分で調べることなく、バージョン番号を省略して依存関係を記述できます。
  2. プラグインの標準設定:
    Javaのコンパイルバージョン(例: Java 21)を指定するmaven-compiler-pluginや、実行可能なJARファイルを生成するspring-boot-maven-pluginなど、推奨されるMavenプラグインが最適なデフォルト設定で組み込まれます。

2-1. 親POMの内容を確認する方法

継承される設定はブラックボックスではありません。

以下の方法で、どのような依存関係やプラグインが管理されているかを正確に確認できます。


方法1:IDEの機能を利用する

IntelliJ IDEAやVS CodeなどのモダンなIDEでは、pom.xml上の<parent>定義から簡単に親POMの内容を追跡できます。

  1. pom.xmlを開き、<artifactId>spring-boot-starter-parent</artifactId>の部分にカーソルを合わせ、Cmd + Click(macOS)またはCtrl + Click(Windows/Linux)を押します。
  2. spring-boot-starter-parentpom.xmlが開かれます。その中にある<dependencyManagement>セクションを見ると、spring-boot-dependenciesimportしていることが分かります。
  3. 同様にspring-boot-dependenciesの定義にジャンプすると、膨大な数のライブラリバージョンが定義された<properties><dependencyManagement>を確認できます。

方法2:Mavenコマンドを利用する

プロジェクトに最終的に適用されるすべての設定(Effective POM)は、Mavenコマンドで確認できます。

  1. プロジェクトのルートディレクトリで、ターミナルから以下のコマンドを実行します。
./mvnw help:effective-pom
  1. コマンドが完了すると、親POMから継承した設定と自身のプロジェクトの設定がすべてマージされた、最終的なpom.xmlの内容が出力されます。ここには、適用されるすべての依存関係のバージョンやプラグインの設定が明記されています。

ITアーキテクトの視点:BOM(Bill of Materials)の活用

プロジェクトによっては、会社の共通設定などを定義した別の親POMを継承したい場合があるかもしれません。Mavenでは複数の親を継承することはできません。

そのようなケースでは、<parent>を継承する代わりに、BOM(Bill of Materials)を利用するアプローチが有効です。spring-boot-dependencies自体がBOMであるため、以下のように<dependencyManagement>セクションで直接インポートできます。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>4.0.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

この方法でも、Spring Bootが管理する依存関係のバージョンを省略できるというメリットを享受できます。ただし、プラグイン管理などは継承されないため、別途設定が必要です。プロジェクトの要件に応じて、<parent>による継承とBOMのインポートを使い分けるのが良いでしょう。


3. プロジェクトの座標:GAVと成果物(アーティファクト)の形式

pom.xmlの中核をなすのが、プロジェクトそのものを定義する情報です。

特に重要なのが、groupId, artifactId, versionの3つで、これらは総称してGAVと呼ばれます。


3-1. GAV:Mavenの世界における「座標」

GAVは、Mavenリポジトリという広大な世界に存在する無数の成果物(アーティファクト)の中から、ただ一つを正確に特定するための「座標(Coordinates)」です。依存関係を追加する際、Mavenはこの座標を頼りに目的のライブラリを探しに行きます。

自分が開発したライブラリを公開する場合、他の人が開発したライブラリを使用する場合に、ライブラリを識別する情報として利用します。

このGAVがなぜ重要なのか、具体的な3つの識別パターンで見ていきましょう。


  1. 自分と他者の成果物(アーティファクト)の識別

あなたの会社の成果物(アーティファクト)と、Springチームが作った成果物(アーティファクト)は、groupIdが異なるため明確に区別されます。これにより、世界中の開発者が公開するライブラリ名が偶然同じでも、衝突することはありません。

<!-- あなたの会社のライブラリ -->
com.mycompany:my-utils:1.0.0

<!-- Springチームのライブラリ -->
org.springframework:spring-core:6.1.0

  1. プロジェクト内での成果物(アーティファクト)同士の識別

あなたが同じgroupId(例: com.mycompany)の中で、複数のライブラリやアプリケーションを開発する場合、それぞれに異なるartifactIdを割り当てることで区別します。

<!-- 認証機能ライブラリ -->
com.mycompany:my-auth-lib:1.2.0

<!-- バッチ処理アプリケーション -->
com.mycompany:my-batch-app:2.0.0

  1. 同じ成果物(アーティファクト)のバージョン間の識別

あるライブラリに機能追加やバグ修正を行った場合、versionを変更することで、過去のバージョンと新しいバージョンを区別します。これにより、プロジェクトは安定した特定のバージョンに依存し続けることができます。

<!-- 最初のリリース -->
com.mycompany:my-auth-lib:1.0.0

<!-- バグ修正版 -->
com.mycompany:my-auth-lib:1.0.1

このように、GAVは単に「自他の区別」だけではなく、「Mavenエコシステムに参加するすべての成果物(アーティファクト)に対する、グローバルで一意な識別子」としての役割を担っています。


では、それぞれの要素を詳しく見ていきましょう。

  • <groupId> (グループID)
    • 位置づけ: プロジェクトを作成した組織やグループを一意に識別するためのIDです。
    • 解説: Javaのパッケージ名と同じく、通常は組織が所有するドメイン名を逆順にしたものが使われます(例: org.springframework.boot, com.google.guava)。これにより、世界規模でのIDの重複を防ぎます。
  • <artifactId> (アーティファクトID)
    • 位置づけ: groupIdというグループの中で、成果物(アーティファクト)そのものを一意に識別するための名前です。
    • 解説: spring-boot-starter-webmodelmapperのように、ライブラリやアプリケーションの具体的な名前が入ります。このgroupIdartifactIdの組み合わせで、特定のプロジェクトが定まります。
  • <version> (バージョン)
    • 位置づけ: 特定のプロジェクトの、特定の時点でのバージョンを識別します。
    • 解説: 3.2.0のように、通常はセマンティックバージョニング(MAJOR.MINOR.PATCH)に準拠した形式が用いられます。同じgroupIdartifactIdでも、バージョンが異なれば別の成果物(アーティファクト)として扱われ、これによりシステムの依存関係を安定させることができます。

3-2. <packaging>:成果物(アーティファクト)の形式を定義する

packaging要素は、このプロジェクトがビルドされた結果、どのような形式の成果物(アーティファクト)になるかを指定します。この指定によって、Mavenのビルドプロセス(ライフサイクル)の挙動が変わります。

  • jar (デフォルト)
    • 解説: Javaのクラスファイルやリソースをまとめた、最も一般的な形式です。ライブラリとして他のプロジェクトから利用されたり、spring-boot-maven-pluginと組み合わせて自己実行可能なアプリケーション(”Fat JAR”)としてパッケージングされたりします。指定しない場合のデフォルト値です。
  • war
    • 解説: Webアプリケーションの形式です。Javaクラスに加えて、HTML/CSS/JavaScriptファイルやWeb設定ファイル(WEB-INF/web.xmlなど)を含みます。この形式の成果物(アーティファクト)は、TomcatやJettyといったサーブレットコンテナにデプロイして実行することを前提としています。
  • pom
    • 解説: 特殊な形式で、これ自体はJARやWARのようなコードを含んだ成果物(アーティファクト)を生成しません。この設定は、主に他のプロジェクトから設定を継承・インポートされることだけを目的とした「親POM」や「BOM (Bill of Materials)」で使用されます。前のセクションで解説したspring-boot-dependenciesも、<packaging>pom</packaging>と定義されています。

コード例:

<groupId>com.techbizplus</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

ITアーキテクトの視点:-SNAPSHOTとは何か?

-SNAPSHOTは「開発中のスナップショット(仮バージョン)」を意味する特別な接尾辞です。

  • 通常のバージョン(例: 1.0.0): 一度リリースされると、内容は不変です。Mavenリポジトリにデプロイされると、上書きはできません。
  • SNAPSHOTバージョン(例: 1.0.0-SNAPSHOT): 開発中であることを示し、Mavenリポジトリにデプロイするたびに上書きされます。

これにより、開発チームは常に最新の開発版ライブラリを参照でき、正式なリリース(1.0.0など)が行われると、そのバージョンは固定され、安定した依存関係として利用できます。
CI/CDパイプラインでは、開発ブランチのビルドではSNAPSHOTとしてデプロイし、リリースブランチのビルドで正式バージョンをデプロイする、といった使い分けが一般的です。


ITアーキテクトの視点:GAVの命名ベストプラクティス

GAVはプロジェクトの「住所」であり、分かりやすく一貫性のある命名は、エコシステム全体の健全性に繋がります。

  • groupIdの決め方: 組織のドメイン名を逆順にするのが鉄則です。もし個人開発でドメインがない場合は、io.github.<あなたのGitHubユーザ名>com.github.<あなたのGitHubユーザ名>といった形式を使うのが現在の一般的な慣習です。これはGitHub上でプロジェクトを管理している場合に、リポジトリの場所と対応がつくため特に分かりやすい方法です。
  • artifactIdのシンプルさ: artifactIdには、プロジェクト名のみを簡潔に記述します。例えばmy-app-1.0のようにバージョン番号を含めるべきではありません。バージョン情報は<version>要素が担うべき責務だからです。

適切な命名規則に従うことで、ライブラリは発見しやすくなり、依存関係の管理も直感的になります。


4. 依存関係の定義:<dependencies><dependency>

プロジェクトで利用する外部ライブラリは<dependencies>要素内で管理します。

Mavenは、ここに記述された情報(GAV)を元に、Maven Central Repositoryなどから必要なライブラリを自動的にダウンロードしてくれます。


4-1. 依存関係のスコープ (<scope>)

<dependency>要素の中でも特に重要なのが、その依存関係がプロジェクトのどのフェーズで有効になるかを定義する<scope>です。

これを適切に設定することで、成果物(アーティファクト)に不要なライブラリが含まれるのを防ぎ、クリーンな状態を保つことができます。

<dependencies>
    <!-- scopeを省略した場合、デフォルトの`compile`になる -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- 実行時にはコンテナから提供されるため、パッケージングには含めない -->
    <dependency>
        <groupId>jakarta.servlet</groupId>
        <artifactId>jakarta.servlet-api</artifactId>
        <scope>provided</scope>
    </dependency>

    <!-- 実行時にのみ必要となるJDBCドライバ -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- テストでのみ利用するライブラリ -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
  • compile (デフォルト): 最も一般的なスコープです。コンパイル、テスト、実行のすべてのフェーズでクラスパスに含まれます。
  • provided: コンパイルやテストの際には必要ですが、実行時にはJDKやWebコンテナ(例: Tomcat)から提供されることを想定した依存関係です。代表例はjakarta.servlet-apiで、WARファイルには含まれません。
  • runtime: コンパイル時には不要ですが、実行時には必要となる依存関係です。JDBCドライバなどがこれに該当します。
  • test: テストコードのコンパイルと実行時にのみクラスパスに含まれます。JUnitやMockitoなどのテスト用ライブラリに指定します。

ITアーキテクトの視点:推移的依存関係とバージョンの競合

Mavenの強力な機能の一つに「推移的依存関係(Transitive Dependencies)」の自動解決があります。
例えば、あなたがspring-boot-starter-webに依存すると、spring-boot-starter-webが依存しているspring-webmvcspring-boot-starter-jsonなども自動的にプロジェクトに追加されます。

これは非常に便利ですが、時として「依存関係の地獄(Dependency Hell)」と呼ばれる問題を引き起こすことがあります。
異なるライブラリが、同じライブラリの異なるバージョンに推移的に依存していると、バージョン競合が発生してしまうのです。

このような状況を調査する方法が、dependency:treeコマンドです。

./mvnw dependency:tree

このコマンドは、プロジェクトの依存関係をツリー形式で表示し、どのライブラリがどのライブラリによって持ち込まれたのかを可視化してくれます。
バージョン競合のトラブルシューティングに不可欠なツールなので、困ったときに使ってみてください。


5. ビルド設定:<build>とMavenライフサイクル

<build>セクションは、ソースコードをどのようにコンパイルし、テストし、パッケージングするかといった、ビルドプロセス全体を定義する場所です。

このセクションを理解する鍵は、「ライフサイクル」と「プラグイン」、そして成果物が保管される「リポジトリ」の概念です。

まず、Mavenが扱う「リポジトリ(成果物の保管場所)」には、大きく分けて2種類あることをイメージしておきましょう。

  • ローカルリポジトリ: あなたのPC内(通常は ~/.m2/repository)にある「自分専用の道具箱」。一度ダウンロードしたライブラリや、自分でビルドした成果物(アーティファクト)(installフェーズで作成)が保管されます。
  • リモートリポジトリ: チームや世界中の開発者と共有する「共有の倉庫」。Maven Central Repositoryや、社内で運用されるNexus/Artifactoryなどがこれにあたります。

5-1. 3つの標準ライフサイクルとフェーズ、プラグイン

Mavenには「ビルドライフサイクル」という、プロジェクトのビルドからデプロイまでの一連の工程を標準化した概念があります。Mavenには、互いに独立した3つの標準ライフサイクルが組み込まれています。

  1. clean: ビルドによって生成されたファイル(targetディレクトリなど)を削除し、プロジェクトをクリーンな状態に戻します。
  2. default: プロジェクトのビルド、テスト、パッケージング、デプロイといった中心的な作業を担います。最も多用されるライフサイクルです。
  3. site: プロジェクトに関する情報からドキュメントサイトを生成します。

これらのライフサイクルは、それぞれが「フェーズ(Phase)」と呼ばれる順序付けられた工程の集まりで構成されています。例えば、mvn installというコマンドを実行すると、Mavenはdefaultライフサイクルの最初からinstallフェーズまでのすべてのフェーズ(validate, compile, test, packageなど)を順番に実行します。

そして、各フェーズで実際の作業を行うのが「プラグイン(Plugin)」です。Mavenは、各フェーズに標準のプラグインゴール(タスク)を紐付けています。


ライフサイクルの全体像

3つのライフサイクルと、defaultライフサイクルの主要なフェーズの流れを視覚的に示すと、以下のようになります。

3つの標準ライフサイクルと、defaultライフサイクルの主要なフェーズの流れ

主要なフェーズと標準プラグイン

ライフサイクル主要なフェーズ担当する主な標準プラグイン役割
cleancleanmaven-clean-plugintargetディレクトリを削除する。
defaultcompilemaven-compiler-pluginソースコード(src/main/java)をコンパイルする。
testmaven-surefire-plugin単体テスト(部品の個別チェック)を実行する。
packagemaven-jar-plugin / maven-war-pluginコンパイル結果をJAR/WARファイルにパッケージングする。
verify(主にmaven-failsafe-plugin用)統合テストの最終チェックを行う品質ゲート。問題があればビルドを停止し、欠陥品のデプロイを防ぐ。
installmaven-install-pluginパッケージをローカルリポジトリ(自分専用の道具箱)にインストールする。
deploymaven-deploy-pluginパッケージをリモートリポジトリ(共有の倉庫)にデプロイする。
sitesitemaven-site-pluginプロジェクトサイト(取扱説明書サイト)のHTMLを生成する。
site-deploymaven-site-plugin生成されたサイトをサーバーにデプロイする。(※)

ITアーキテクトの視点:各フェーズの役割を身近な例で理解しよう

表の各フェーズが何をしているのか、その目的を身近な例で補足しましょう。

  • install: 「自分専用の道具箱」への整理
    自分で作った便利な工具(ライブラリ)を、後で別の作業でも使えるように自分の道具箱にしまっておくイメージです。PC内の他のプロジェクトから参照できるようになります。
  • deploy: 「共有の倉庫」への納品
    完成した製品(ライブラリ)を、チーム全員が使えるように共有の倉庫に納品するイメージです。CI/CDサーバーがこの役割を担うことが多いです。
  • verify: 「最終品質チェックの門番」
    車で例えるなら、packageで車体を組み立て、integration-testでテストコースを走行させます。verifyは、その走行結果をチェックし、ブレーキが効かないなどの欠陥が見つかった成果物(アーティファクト)が、決してinstall(保管)やdeploy(出荷)に進まないようにする「門番」です。
  • sitesite-deploy: 「取扱説明書の作成と公開」
    siteはプロジェクトの仕様やテスト結果をまとめた「取扱説明書サイト」を自動生成する機能です。そしてsite-deployは、その出来上がったサイトを、みんなが見られるWebサーバーに「公開(展示)」する作業です。

(※) site-deployのデプロイ先はどこ? (現代的な手法)

site-deployのデプロイ先は、pom.xml<distributionManagement>セクションで指定します。現在では、scpのような古典的な方法よりも、GitHub Pagesのような静的ホスティングサービスへデプロイするのが一般的です。

GitHub Pagesへのデプロイ例:

  1. pom.xmlの設定:
    サイトの生成場所と、ソースコード管理(SCM)の接続情報をpom.xmlに追記します。これにより、maven-scm-publish-pluginがデプロイ先を認識できるようになります。
 <distributionManagement>
     <site>
         <id>github</id>
         <name>GitHub Pages</name>
         <url>scm:git:https://github.com/your-username/your-repo.git</url>
     </site>
 </distributionManagement>
 
 <scm>
     <connection>scm:git:https://github.com/your-username/your-repo.git</connection>
     <developerConnection>scm:git:https://github.com/your-username/your-repo.git</developerConnection>
     <url>https://github.com/your-username/your-repo</url>
 </scm>

  1. 認証情報の設定 (~/.m2/settings.xml):
    ローカルから手動でデプロイする場合、GitHubへの書き込み権限を持つパーソナルアクセストークン(PAT)settings.xmlに設定します。<id><distributionManagement>で指定したものと一致させます。
 <settings>
   <servers>
     <server>
       <id>github</id>
       <username>your-username</username>
       <password>YOUR_PERSONAL_ACCESS_TOKEN</password>
     </server>
   </servers>
 </settings>

CI/CD環境でのベストプラクティス:

settings.xmlにトークンを直接記述する方法は、ローカルでの一時的な作業には便利ですが、セキュリティリスクが伴います。

GitHub ActionsのようなCI/CD環境では、ワークフロー内で提供されるsecrets.GITHUB_TOKENや、リポジトリに安全に保管された暗号化シークレットを利用するのが鉄則です。これにより、認証情報をソースコードやローカルファイルに一切残すことなく、安全にデプロイパイプラインを構築できます。


よく使われるコマンド実行パターン

実際には、これらのライフサイクルやフェーズを組み合わせて実行するのが一般的です。

  • mvn clean install
    • 内容: プロジェクトをクリーンにし、ビルド、テスト、パッケージングを経て、成果物(アーティファクト)をローカルリポジトリにインストールします。
    • ユースケース: 最も頻繁に使われるコマンド。ローカル環境で開発中のライブラリを、別のプロジェクトから参照できるようにする場合などに使用します。
  • mvn clean package
    • 内容: ローカルリポジトリにはインストールせず、targetディレクトリにJAR/WARファイルを作成するところまでを実行します。
    • ユースケース: Dockerイメージを作成する際など、単純にビルド成果物(アーティファクト)ファイルのみが必要な場合に使います。
  • mvn clean deploy
    • 内容: ビルド成果物(アーティファクト)をリモートリポジトリ(Artifactory, Nexusなど)にデプロイします。
    • ユースケース: 主にCI/CDサーバーが、他の開発者やチームとライブラリを共有するために実行します。
  • mvn verify
    • 内容: packageまで実行し、さらに統合テストを走らせてその結果を検証します。
    • ユースケース: 成果物(アーティファクト)をローカルリポジトリにインストールする前の最終品質確認として使用します。
  • mvn site-deploy
    • 内容: プロジェクトのドキュメントサイトを生成し、pom.xmlで指定されたサーバーに公開します。
    • ユースケース: プロジェクトの技術情報をチームに共有する場合などに使用します。
  • mvn clean package -DskipTests
    • 内容: cleanpackageを実行しますが、-DskipTestsフラグによってテストの実行をスキップします。
    • ユースケース: ドキュメントの生成など、テストを実行する必要がない状況でビルド時間を短縮したい場合に使用します。

プラグインのカスタマイズ:<build>セクション

ここまではライフサイクルの流れと、それを実行するコマンドの例を見てきました。

最後に、これらの各フェーズで実際に動いている「プラグイン」を、<build>セクションでどのようにカスタマイズするのかを見ていきましょう。

<build>セクションは、まさにそのプラグインの挙動を定義したり、新たなプラグインを追加したりする場所です。

代表的な例として、spring-boot-maven-pluginや、テストの挙動を制御するmaven-surefire-pluginの設定を見てみましょう。

<build>
    <plugins>
        <!-- spring-boot-starter-parentで定義済みのプラグイン。
             特別な設定を追加したい場合に記述する。 -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>

        <!-- surefireプラグインの挙動をカスタマイズ -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <!-- 親POMでバージョンが管理されているため、通常はバージョン指定は不要 -->
            <configuration>
                <!-- `-DskipTests=true` と同じ効果 -->
                <skipTests>true</skipTests>
            </configuration>
        </plugin>
    </plugins>
</build>

このコード例では、2つのプラグインが定義されています。

  1. spring-boot-maven-plugin:
    Spring Bootアプリケーションを実行可能なJARファイルにパッケージングする重要なプラグインです。
    この例では<configuration>がないため、親POMで定義されたデフォルトの設定をそのまま利用しています。
  2. maven-surefire-plugin (カスタマイズの主役):
    単体テストを実行する標準プラグインですが、ここでは<configuration>で挙動が変更されています。
    <skipTests>true</skipTests>という設定は、このプロジェクトのビルド時に単体テストを常にスキップすることを意味します。
    これは、コマンドラインで-DskipTests=trueオプションを毎回指定するのと同じ効果があります。

ITアーキテクトの視点:なぜテストをスキップするのか?

テストは品質の生命線ですが、あえてスキップする設定が使われることもあります。

例えば、「現在リファクタリング中で多くのテストが一時的に失敗するが、動作確認のためにビルドは通したい」といった状況や、「このプロファイルはドキュメント生成専用なので、ビルド時間短縮のためにテストは不要」といった特定のユースケースが考えられます。

ただし、恒久的にテストをスキップする設定は、品質低下に直結する可能性があるため、その利用は慎重に行うべきです。


6. プロパティの活用:<properties>で設定を集中管理する

<properties>セクションは、POMファイル内で利用する値を一元管理するための仕組みです。

バージョン番号などの設定値を一箇所にまとめておくことで、繰り返しを避け(DRY原則)、POMの保守性を大幅に向上させることができます。


6-1. プロパティの種類と使い方

プロパティは${}という構文で参照します。主に以下の種類があります。

  1. ユーザー定義プロパティ
    <properties>内で自由に定義できるプロパティです。親POMで管理されていないライブラリのバージョン番号などを定義するのによく使われます。
<properties>
    <java.version>25</java.version>
    <modelmapper.version>3.2.0</modelmapper.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.modelmapper</groupId>
        <artifactId>modelmapper</artifactId>
        <version>${modelmapper.version}</version>
    </dependency>
</dependencies>
  1. Maven組み込みプロパティ
    POMの要素やsettings.xmlの値にアクセスするための、予約済みのプロパティです。
  • project.*: POMの各要素を参照します。例えば、${project.version}でプロジェクトのバージョンを取得できます。
  • settings.*: ~/.m2/settings.xmlで定義した値を参照します。

spring-boot-starter-parentを使っている場合、Javaのバージョンは<properties>内の<java.version>で指定するのが標準的な方法です。Java 25は2025年9月にリリースされた最新のLTS(長期サポート)バージョンです。プロジェクトの要件に応じて、同じくLTSであるJava 21や17を選択することも一般的です。

親POM側でこのプロパティを読み取り、maven-compiler-pluginに渡してくれる仕組みになっています。


ITアーキテクトの視点:Javaバージョンの指定方法と<release>オプション

Spring Bootの親POMは、私たちが指定した<java.version>プロパティを、内部でmaven-compiler-plugin<source>(ソースコードの言語レベル)と<target>(生成されるバイトコードの互換レベル)という2つの設定に自動で変換してくれます。

一方、Java 9以降のプロジェクトでは、<release>という単一のオプションを使うことが推奨されています。

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <release>25</release>
    </configuration>
</plugin>

<release>オプションは、<source><target>をまとめて指定するだけでなく、コンパイル時に使用するJDKが、対象のJavaバージョン(この例では25)に標準搭載されているAPIのみを参照するように制限をかけてくれます。これにより、意図せず新しいバージョンのAPIを使ってしまい、古い実行環境で動かなくなる、といった事故を防ぐことができます。

Spring Bootプロジェクトでは<java.version>プロパティを使うのが手軽で一般的ですが、より厳密なビルドを行いたい場合は<release>オプションの利用を検討する価値があります。


ITアーキテクトの視点:プロファイルとプロパティの連携

<properties>の真価は、ビルド環境ごとに設定を切り替える「プロファイル(Profiles)」と組み合わせることで発揮されます。

<profiles>セクションでは、特定の条件下で有効になる設定のグループを定義できます。例えば、開発環境(デフォルト)と本番環境で、適用する設定プロパティを切り替えることができます。

<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <api.endpoint>http://localhost:8080/api</api.endpoint>
        </properties>
    </profile>
    <profile>
        <id>prod</id>
        <properties>
            <api.endpoint>https://api.example.com</api.endpoint>
        </properties>
    </profile>
</profiles>

このように定義しておくと、通常はdevプロファイルが有効になりますが、./mvnw package -P prodのように-Pオプションでプロファイルを指定することで、本番環境向け(prod)のプロパティを適用したビルドが可能になります。
これは、環境ごとに異なるデータベース接続情報やAPIエンドポイントを管理する上で有効な手法です。


まとめ:POM.xmlの基本を理解する

本記事では、Mavenプロジェクトの根幹をなすpom.xmlと、標準的なディレクトリ構造について解説しました。

  • 標準ディレクトリ構造: 「設定より規約」という考え方に基づき、ビルドの自動化を支援します。targetディレクトリはビルド時に自動生成されるため、Gitの管理対象から除外するのが一般的です。
  • 親POM (<parent>): spring-boot-starter-parentなどを継承することで、依存ライブラリのバージョン管理やプラグイン設定を大幅に簡略化できます。
  • GAVと-SNAPSHOT: プロジェクトを一意に識別するための座標(GAV)と、開発中のバージョンを示す-SNAPSHOTについて説明しました。
  • 依存関係管理: <dependencies>要素で利用するライブラリを宣言的に管理する方法を紹介しました。
  • プロパティの活用: <properties>要素でバージョン番号などを一元管理し、pom.xmlの保守性を高める方法について解説しました。

これらの知識は、Mavenを効果的に利用するための基礎となります。pom.xmlが単なる設定ファイルではなく、プロジェクトの構成やビルドの方法を定義する重要な役割を持つことをご理解いただけたと思います。

次回の記事では、さらに一歩進んで「依存関係の管理とトラブルシューティング」について解説する予定です。依存関係の競合解決など、より実践的なテクニックを紹介しますので、ぜひご覧ください!


免責事項

本記事に記載されているバージョン情報(Spring Boot, Java等)や設定例は、記事執筆時点(2026年1月)のものです。お使いの環境や将来のバージョンアップにより、コマンドの実行結果や推奨される設定が異なる場合があります。最新の情報は、必ず公式サイトのドキュメントをご確認ください。


SNSでもご購読できます。

コメントを残す

*