Maven覚書

## はじめに
初めてjavaを使って開発する機会がありビルドツールとしてMavenを採用しました。
開発環境を設定する際になんとなくで使用していたため、自分の理解のためにまとめてみました。

## Mavenとは
MavenはApatche Software Foundationで開発されたソフトウェアプロジェクト管理ツールです。読み方は「メイヴェン」。Project Object Model(POM)と呼ばれるXML形式のファイル情報に基づき、プロジェクトの新規作成からコンパイル、テスト、パッケージング、配備などのプロジェクトのライフサイクルやライブラリの依存関係の管理などが行えます。理解ツールという面もあり、Mavenを利用したプロジェクトではビルドプロセスやプロジェクトの構成などがデフォルトで決まっているため、全体把握がしやすいというメリットがあります。

Mavenのアーキテクチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652620/dfc263e2-5fa7-3fa6-6de9-16f4300f0bcd.png)
[参考](https://www.techscore.com/tech/Java/ApacheJakarta/Maven/2/)
Mavenを使用するとコンパイルやテストなどプロジェクトのライフサイクルの作業をコマンド一つで実行することができます。リモートリポジトリとローカルリポジトリは使用されるプラグインとライブラリが配置される場所になります。Mavenコマンド実行時に必要なプラグインやライブラリがリモートリポジトリからローカルリポジトリにダウンロードされ参照されます。


## インストール
[こちら](https://maven.apache.org/download.cgi)からzipをインストールします。
現在（2023/11）の最新バージョンは3.9.5です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652620/559795f0-2f81-7698-9b76-28857dbc8f9d.png)
任意の場所にzipの解凍後`**\apache-maven-3.9.5\bin`をシステム環境変数Pathに追加してください。
`mvn -v`を実行しバージョン情報が表示されたらOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652620/690c9669-8ddc-453f-14b9-e9ab912e235e.png)

:::note info
補足
Mavenには[Maven Wrapper](https://maven.apache.org/wrapper/index.html)と呼ばれる、Mavenを自動ダウンロードし各操作ができるラッパーがあります。各開発者わざわざMavenをインストールする必要がなくなるので、実際のプロジェクトではMaven Wrapperを使用もありだと思います。Maven Wrapperを使用する場合は、mvnコマンドの代わりにmvnw.cmdを叩く形になります。実際に開発ではMaven Wrapperを使用していました。
:::

## プロジェクトの作成
新しくMavenのプロジェクトを立ち上げるには[Archetype Plugin](https://maven.apache.org/archetype/maven-archetype-plugin/)を使用してテンプレートからプロジェクトを作成するのが手っ取り早いです。例えば以下のようなコマンドを実行します。
```
$ mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false
```
プラグインにはゴールと呼ばれる実行される処理がいくつか存在します。上記コマンドではarchetypeプラグインのgenerateゴールを実行しています。-Dではその処理に対するパラメータを指定でき、mavenプロジェクトで必要な`groupId`を`com.mycompany.app`、`artifactId`を`my-app`に指定しています。またarchetypeにはいくつか種類が存在しており、今回は`maven-archetype-quickstart`と呼ばれるarchetypeが指定されます。archetypeはプロジェクトに合わせて選択する感じになると思います。
[archetype一覧](https://maven.apache.org/archetypes/index.html)

:::note info
※補足
vscodeを使用して開発を行う場合は[Maven for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-maven)を使うとGUIベースでテンプレートを作成できます。
:::
## ディレクトリ構造
Mavenでは標準となるディレクトリ構造が決まっており、それに従うことが推奨されています。ディレクトリ構造を考える手前も減りますし、Mavenプロジェクトであれば同一のディレクトリ構造となるので他プロジェクトへの参画もしやすいというメリットもあるので、特に問題がなければ従うのが良いと思います。
例えば先ほどのコマンドでは以下のような構成でプロジェクト作成されています。
```
my-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- com
    |           `-- mycompany
    |               `-- app
    |                   `-- App.java
    `-- test
        `-- java
            `-- com
                `-- mycompany
                    `-- app
                        `-- AppTest.java
```
以下がディレクトリ構造の決まりです。
|ディレクトリ|説明|
|--------|------|
|src/main/java|アプリケーション・ライブラリのソースコード|
|src/main/resources|アプリケーション・ライブラリのリソース|
|src/main/filters|リソースに適用するフィルタ|
|src/main/webapp|Webアプリケーションのソース|
|src/test/java|テストのソースコード|
|src/test/resources|テストのリソース|
|src/test/filter|テストリソースに適用するフィルタ|
|src/it|統合テスト用|
|src/assembly|アセンブリ記述子。 配布用ファイル (zip や tar.gz など) の作成に関する情報。|
|src/site|サイトの作成に必要なファイル|

[Introduction to the Standard Directory Layout](https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html)


## POM
pom.xmlはプロジェクトに関する情報を持つMavenにおいて核となる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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>my-app</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>

```
上記のpom.xmlの構成は大まかな内容は以下になります。
|パラメータ|説明|
|--------|------|
|project|最上位要素。必須。|
|modelVersion|POMのバージョン。必須。|
|groutId|プロジェクトを作成した組織またはグループの一意の識別子を指定する。依存関係解決のなど一意に認識するために使用されたりする。必須。|
|artifactId|一次成果物の一意なベース名を指定する。パッケージングの際は{artifactId}-{version}.jarの形で生成される。必須。|
|version|バージョン情報。SNAPSHOTは開発中を意味する。必須。|
|name|プロジェクトの名前。Mavenで生成されたドキュメント内で使用される。|
|url|プロジェクトのurl。Mavenで生成されたドキュメント内で使用される。|
|properties|pom内でアクセスできる値のプレースホルダーの指定ができる。プレースホルダの文字列はpluginで決められている場合もあれば、任意で指定する事もできる。上記では用意されている`maven.compiler.target`と`maven.compiler.source`のプロパティに対してjavaのバージョン情報が指定されている。|
|dependencies|依存関係を列挙する。上記では`junit`という単体テストライブラリが追加されている。|
|build|ディレクトリ構造の宣言やプラグインの管理を行う。上記では各プラグインのバージョン指定をしている。|

pomにはSuper Pomと呼ばれるデフォルトのpomが存在します。プロジェクトのpomで値の指定がない場合は、このSuper Pomの値が継承されます。

[POM Reference](https://maven.apache.org/pom.html)
[Introduction to the POM](https://maven.apache.org/guides/introduction/introduction-to-the-pom.html)
[Super POM](https://maven.apache.org/ref/3.9.5/maven-model-builder/super-pom.html)

## ビルドライフサイクル

Mavenではビルドのプロセスが明確に定義されています。ユーザーはコマンドで各プロセスを実行することができます。組み込みでは`default`、`clean`、`site`の三つのビルドサイクルが存在します。それぞれ`default`はデプロイ処理、`clean`はクリーニング処理,`site`はプロジェクトのWebサイト作成の処理をします。

### フェーズ
ライフサイクルはいくつかのフェーズで構成されています。例えば`default`のライフサイクルは以下のようなフェーズがあります。

|フェーズ|説明|
|--------|------|
|validate |プロジェクトが正しく、必要な情報がすべて利用可能であることを検証する。|
|compile|プロジェクトのソースコードをコンパイルする。|
|test|コンパイルされたソースコードをテストする。|
|package|コンパイルされたコードを取得しJARやWARなどの配布可能な形式にパッケージ化する。|
|verify|統合テストの結果に関するチェックを実行する。|
|install|ローカルの他のプロジェクトの依存関係として使用するために、パッケージをローカルリポジトリにインストールする。|
|deploy|ビルド環境で実行され、他の開発者やプロジェクトと共有するために最終パッケージをリモートリポジトリにコピーする。|

[Lifecycle Reference](https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#lifecycle-reference)

### 実行
各フェーズを実行するには、`mvn {フェーズ}`で対象のフェーズまで実行がされます。
最初の実行では必要なすべてのプラグインと依存関係をリモートリポジトリからローカルリポジトリにダウンロードするため時間がかかります。二回目以降はローカルリポジトリから参照されるようになるため実行時間が短縮されます。
以下から主に使うであろうフェーズの説明を記載します。
#### compile
```
$ mvn compile
```
上記コマンドでコンパイルされたクラスはデフォルトで`${project.basedir}/target/classes`に配置されます。これもMavenが標準的なディレクトリ構成規約に従っています。

#### test
テストの実行
```
$ mvn test
```
テストを実行で使用されるsurefireプラグインは、特定の命名規則を持つファイルがテストとして識別されます。デフォルトでは以下のファイルが対象になります。
`**/*Test.java`
`**/Test*.java`
`**/*TestCase.java`
以下のファイルがデフォルトで除外されます。
`**/Abstract*Test.java`
`**/Abstract*TestCase.java`

テストコンパイルのみ
```
$ mvn test-compile
```

#### package
JARやWRAなどの成果物の生成
```
$ mvn package
```
上記コマンドでは`${project.basedir}/target`にファイルが生成されます。デフォルトではJARファイルになります。上で作成したプロジェクトではmy-app-1.0-SNAPSHOT.jarというファイルが出来上がるはずです。

#### clean
```
$ mvn clean
```
`${project.basedir}/target`を削除します。
また以下のようにcleanした後にpackage実行といった操作もできます。
```
$ mvn clean package
```

## プラグイン
Mavenの処理はプラグインによって実行されています。例えばJARにパッケージングする場合は各フェーズでは以下のようなプラグインのゴールに紐づいています。pom.xmlでバージョンが指定されていなければ、最新のプラグインがダウンロードされて実行されます。
|フェーズ|	プラグイン：ゴール|
|-----|-----|
|process-resources|	resources:resources|
|compile|	compiler:compile|
|process-test-resources|resources:testResources|
|test-compile|compiler:testCompile|
|test|surefire:test|
|package|jar:jar|
|install|install:install|
|deploy|deploy:deploy|

何のプラグインが実行されているかは、フェーズ実行時に出力されている情報からも確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652620/391ab879-66c7-cbef-8830-e66eb9f313d2.png)
利用できるプラグイン一覧は以下参照。
[Available Plugins](https://maven.apache.org/plugins/index.html)

pomになにも記載しなければデフォルトの設定で各プラグインのゴールが実行されます。プラグインごとにさまざまなパラメータが用意されてるため、それぞれ設定するにはpom.xmlの`build/plugins`内で指定します。
以下ではcompiler pluginでターゲットとなるJDKのバージョンを指定しています。
```
 <build>
   <plugins>
     <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-compiler-plugin</artifactId>
       <version>3.3</version>
       <configuration>
         <release>17</release>
       </configuration>
     </plugin>
   </plugins>
 </build>
 ```
[Guide to Configuring Plug-ins](https://maven.apache.org/guides/mini/guide-configuring-plugins.html)
　
## 依存関係
必要な依存関係はすべてpom.xmlに記載していく必要があります。
上で作成したプロジェクトではJUnitが依存関係に含まれています。
```
<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
```
ここでは依存関係ごとに、`groupId`、`artifactId`、`version`、`scope`の少なくとも4つを定義する必要があります。`groupId`、`artifactId`、`version`は対象のプロジェクトのpom.xmlで指定されているものと同じです。`scope`パラメータではプロジェクトがどのタイミング依存関係を解決するかを以下のような選択肢から指定できます。
|値|	説明|
|-----|-----|
|compile|	デフォルト値。常に必要な場合。|
|provided|コンパイルやテストでは必要だが、実行時には実行環境が提供してくれる場合。|
|runtime|コンパイル時には必要なく実行時に必要な場合。|
|test|テストのコンパイル・実行時に必要な場合。|
|system|依存関係がシステム(実行環境のJREやJDK)から提供されるものである事を示す。|

[Introduction to the Dependency Mechanism](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)

## リポジトリ
Mavenでは依存関係はリポジトリから参照されます。
デフォルトではリモートリポジトリは[Maven Central Repository](https://repo.maven.apache.org/maven2/)になります。またはMaven Central Repositoryに加えて使用する独自のリモートリポジトリ（社内だけで共通で使用できるリポジトリなど）も設定することもできます。ローカルリポジトリはMavenを実行するPC上のディレクトリ（デフォルトは${user.home}/.m2/repository）でリモートリポジトリからダウンロードされたライブラリが含まれます。
[Introduction to Repositories](https://maven.apache.org/guides/introduction/introduction-to-repositories.html)

## おわりに
Maven全体の理解を深めることができました。
このあたりを知っておけばひとまずは迷うことなくmavenを使用できると思います。ライブラリやプラグインの細かい設定などは必要に応じて各々ドキュメントを見に行くのがよいでしょう。