Apache Maven
ビルドツール
Apache Maven
概要
Apache Mavenは、主にJavaプロジェクト向けの包括的なプロジェクト管理・ビルド自動化ツールです。2004年にApache Software Foundationによって開発され、「Project Object Model (POM)」と呼ばれるXMLベースの設定ファイルを使用してプロジェクトの構造、依存関係、ビルドプロセスを管理します。「設定より規約(Convention over Configuration)」の原則に基づき、標準的なディレクトリ構造とライフサイクルを提供することで、Javaエコシステムにおけるデファクトスタンダードとなっています。Spring Framework、Apache Commons、Hibernateなど多くの主要なJavaプロジェクトで採用されています。
詳細
主要機能
- 依存関係管理: 自動的なライブラリダウンロードと依存関係解決
- 標準ライフサイクル: validate、compile、test、package、install、deployの標準プロセス
- プロジェクト構造標準化: 一貫したディレクトリレイアウトとベストプラクティス
- プラグインアーキテクチャ: 拡張可能なプラグインシステム
- マルチモジュール対応: 複数プロジェクトの統合管理
- レポート生成: Javadoc、テストレポート、コード品質レポート
- IDE統合: Eclipse、IntelliJ IDEA、NetBeansでの優れたサポート
アーキテクチャ
POM(Project Object Model)によるプロジェクト記述、標準ライフサイクルによるビルドフェーズ管理、Maven Central Repositoryを中心とした依存関係管理システム。
エコシステム
Maven Central Repository、Maven Plugin Registry、IDE統合、CI/CDツール(Jenkins、GitHub Actions等)との連携、GradleやSBTとの併存。
メリット・デメリット
メリット
- 業界標準: Javaエコシステムのデファクトスタンダード
- 依存関係管理: 強力で信頼性の高い依存関係解決システム
- 標準化: 一貫したプロジェクト構造とベストプラクティス
- 豊富なプラグイン: 包括的なプラグインエコシステム
- IDE統合: 優れた開発環境統合とサポート
- エンタープライズサポート: 企業環境での豊富な実績と信頼性
- 豊富なドキュメント: 充実した公式ドキュメントとコミュニティリソース
デメリット
- 設定の複雑さ: 大規模プロジェクトでは pom.xml が複雑化
- XML記述: 冗長なXML記述の必要性
- パフォーマンス: 大規模プロジェクトでのビルド時間の長さ
- 柔軟性の制約: 規約に従わない場合の設定の複雑さ
- 依存関係競合: 複雑なトランザクティブ依存関係問題
- 学習コストの転換: 他のビルドツールへの移行時の学習コスト
参考ページ
- Apache Maven 公式サイト
- Maven スタートガイド
- Maven リファレンス
- Maven プラグイン一覧
- Maven Central Repository
- Maven GitHub リポジトリ
書き方の例
インストールとプロジェクトセットアップ
# Maven インストール確認
mvn -version
# Javaバージョン確認
java -version
# 新しいMavenプロジェクト作成
mvn archetype:generate \
-DgroupId=com.example.myapp \
-DartifactId=my-app \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
# プロジェクトディレクトリに移動
cd my-app
# 基本的なMavenコマンド
mvn clean # 生成ファイル削除
mvn compile # コンパイル
mvn test # テスト実行
mvn package # JARファイル作成
mvn install # ローカルリポジトリにインストール
mvn clean install # クリーンビルド
mvn site # サイト・レポート生成
# ヘルプ表示
mvn help:describe -Dplugin=compiler
基本的な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>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!-- プロジェクト情報 -->
<name>My Application</name>
<description>Sample Maven application</description>
<url>https://github.com/example/my-app</url>
<!-- プロパティ設定 -->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.9.2</junit.version>
<logback.version>1.4.6</logback.version>
</properties>
<!-- 依存関係 -->
<dependencies>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- SLF4J + Logback -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- Apache Commons Lang -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
<!-- ビルド設定 -->
<build>
<plugins>
<!-- Maven Compiler Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<!-- Maven Surefire Plugin (Tests) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M9</version>
</plugin>
</plugins>
</build>
</project>
Spring Bootアプリケーションの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>
<!-- Spring Boot Parent POM -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-boot-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Spring Boot Application</name>
<description>Spring Boot web application</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2022.0.3</spring-cloud.version>
</properties>
<dependencies>
<!-- Spring Boot Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Spring Boot Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Spring Boot Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- H2 Database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- PostgreSQL Driver -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Security Test -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Spring Cloud BOM -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!-- Spring Boot Maven Plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<!-- Maven Failsafe Plugin (Integration Tests) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
</plugins>
</build>
<!-- プロファイル -->
<profiles>
<profile>
<id>dev</id>
<properties>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<spring.profiles.active>prod</spring.profiles.active>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>false</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
マルチモジュールプロジェクト
<!-- 親プロジェクトの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>com.example</groupId>
<artifactId>multi-module-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Multi-Module Application</name>
<description>Parent project for multi-module application</description>
<!-- モジュール定義 -->
<modules>
<module>common</module>
<module>core</module>
<module>web</module>
<module>integration-tests</module>
</modules>
<!-- 共通プロパティ -->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- バージョン管理 -->
<spring-boot.version>3.1.0</spring-boot.version>
<junit.version>5.9.2</junit.version>
<mockito.version>5.3.1</mockito.version>
<assertj.version>3.24.2</assertj.version>
</properties>
<!-- 依存関係管理 -->
<dependencyManagement>
<dependencies>
<!-- Spring Boot BOM -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 内部モジュール -->
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>core</artifactId>
<version>${project.version}</version>
</dependency>
<!-- テスト依存関係 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 共通ビルド設定 -->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M9</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M9</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
<!-- コアモジュールのpom.xml (core/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>
<!-- 親プロジェクト参照 -->
<parent>
<groupId>com.example</groupId>
<artifactId>multi-module-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>core</artifactId>
<packaging>jar</packaging>
<name>Core Module</name>
<description>Core business logic module</description>
<dependencies>
<!-- 内部モジュール依存 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>common</artifactId>
</dependency>
<!-- Spring Framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<!-- テスト依存関係 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
高度なプラグイン設定とレポート生成
<?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>com.example</groupId>
<artifactId>advanced-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- プラグインバージョン -->
<maven-checkstyle-plugin.version>3.2.1</maven-checkstyle-plugin.version>
<spotbugs-maven-plugin.version>4.7.3.0</spotbugs-maven-plugin.version>
<jacoco-maven-plugin.version>0.8.8</jacoco-maven-plugin.version>
<maven-site-plugin.version>4.0.0-M7</maven-site-plugin.version>
</properties>
<dependencies>
<!-- アプリケーション依存関係 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.0</version>
</dependency>
<!-- テスト依存関係 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Maven Compiler Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- JaCoCo Plugin (Code Coverage) -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>INSTRUCTION</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<!-- Checkstyle Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${maven-checkstyle-plugin.version}</version>
<configuration>
<configLocation>checkstyle.xml</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
</configuration>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- SpotBugs Plugin -->
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>${spotbugs-maven-plugin.version}</version>
<configuration>
<effort>Max</effort>
<threshold>Low</threshold>
<xmlOutput>true</xmlOutput>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Maven Site Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>${maven-site-plugin.version}</version>
</plugin>
<!-- Maven Release Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<autoVersionSubmodules>true</autoVersionSubmodules>
<useReleaseProfile>false</useReleaseProfile>
<releaseProfiles>release</releaseProfiles>
<goals>deploy</goals>
</configuration>
</plugin>
</plugins>
</build>
<!-- レポート設定 -->
<reporting>
<plugins>
<!-- Maven Project Info Reports -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.4.2</version>
</plugin>
<!-- JavaDoc Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.5.0</version>
</plugin>
<!-- JaCoCo Report -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin.version}</version>
<reportSets>
<reportSet>
<reports>
<report>report</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<!-- Checkstyle Report -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${maven-checkstyle-plugin.version}</version>
<reportSets>
<reportSet>
<reports>
<report>checkstyle</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<!-- SpotBugs Report -->
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>${spotbugs-maven-plugin.version}</version>
</plugin>
</plugins>
</reporting>
<!-- プロファイル -->
<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<!-- Maven Source Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Maven JavaDoc Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
カスタムライフサイクルとプラグイン開発
# カスタムMavenコマンド実行例
# 品質チェック実行
mvn clean compile checkstyle:check spotbugs:check
# テストカバレッジ測定
mvn clean test jacoco:report
# サイト生成(レポート含む)
mvn clean site
# リリース準備
mvn release:prepare
# リリース実行
mvn release:perform
# 依存関係分析
mvn dependency:tree
mvn dependency:analyze
# プラグイン情報表示
mvn help:describe -Dplugin=org.springframework.boot:spring-boot-maven-plugin
# 有効なプロファイル表示
mvn help:active-profiles
# プロジェクト情報表示
mvn help:effective-pom
mvn help:effective-settings
# デバッグモード実行
mvn clean install -X
# オフラインモード
mvn clean install -o
# 並列ビルド
mvn clean install -T 4
# 特定のテストのスキップ
mvn clean install -DskipTests
# 統合テストのみ実行
mvn clean verify -DskipUnitTests