Mavenとは?
一言でいえば、「ソフトウェアのプロジェクト管理ツール」です。
Apacheソフトウェア財団というアメリカの非営利団体が開発しています。
対応言語は基本的にJavaです。
Java以外の言語でMavenを使用することも可能ですが、その言語をサポートするプラグインが必要になる模様です。
何が嬉しいのか?
「プロジェクト管理」とは何をするかというと、
・プロジェクトに必要なモジュールの自動ダウンロード
・コンパイル
・テストの実行
・パッケージング
・成果物の配備
などです。
何が嬉しいのか?は色々ありますが、ざっくり書くと以下の2つが大きいです。
■依存関係の解決が楽になる■
プロジェクトがモジュールAを使うとき、一般に「プロジェクトはモジュールAに依存する」と表現されます。
この時、モジュールAはさらにモジュールBやCに依存し、モジュールBやCはさらにさらにモジュールDやEに依存しているということが多いです。
Mavenを使わない場合、これらの必要なモジュールをひとつひとつダウンロードしなければならず、かなり管理が面倒ですが、Mavenでは、設定ファイルであるpom.xmlにモジュールAを記載するだけで、モジュールB以下を自動的にダウンロードしてくれるのです。よって、複数人で開発するときにありがちな「モジュールのバージョンが違ったので挙動が異なる」というような煩雑な問題が発生しなくなります。
これを「依存関係の解決」といいます。これが最大のメリットではと思います。
■ビルドが楽になる■
プロジェクトのコンパイル、テスト実行、そしてjarファイルなどに固めるといった一連の流れを、コマンドを実行するだけで実行できます。プロジェクト間での一貫性が保たれ、新しいメンバーがプロジェクトに参加したときの学習負荷が軽減されます。
pom.xmlについて
mavenの設定ファイルとして非常に重要なのが、pom.xmlです。
(pomとは、「project object model」の略です)
pom.xmlには何を書くのでしょうか?
全て書くと切りがないので、ここでは最も重要なタグについてのみ書きます。
それはdependencyタグです。
【dependency】
上述した通り、プロジェクトがモジュールAを使うとき、一般に「プロジェクトはモジュールAに依存する」と表現されます。dependencyタグには、依存するモジュールを記載します。
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>2.7.3</version>
<scope>test</scope>
</dependency>
ではこのモジュールの実態は何でしょうか?それは(基本的に)jarファイルです。
jarファイルについて
jarとは「Java Archive」の略です。
アーカイブ、つまりJava開発で利用するファイルをまとめたファイルということになります。
何が嬉しいかというと、ひとつのファイルに統合することで、Java環境で実行するソフトウェアや資源の配布を容易にすることができるのです。
簡単に言えば、Java版のzipファイルです。
内部的にはzip圧縮を使っているので、実際にjarファイルの拡張子をzipに変更して解凍することで中身を確認できます。以下は、試しにテキトーにzipに変更して解凍した結果のフォルダ/ファイル構成です。
treeコマンドの結果
├─META-INF
│ │ license.txt
│ │ MANIFEST.MF
│ │ notice.txt
│ │ spring-web.kotlin_module
│ │ web-fragment.xml
│ │
│ ├─native-image
│ │ └─org.springframework
│ │ └─spring-web
│ │ native-image.properties
│ │
│ ├─services
│ │ jakarta.servlet.ServletContainerInitializer
│ │ reactor.blockhound.integration.BlockHoundIntegration
│ │
│ └─spring
│ aot.factories
│
└─org
└─springframework
├─http
│ │ CacheControl.class
│ │ ContentDisposition$Builder.class
中略
│ │ StreamingHttpOutputMessage$Body.class
│ │ StreamingHttpOutputMessage.class
│ │ ZeroCopyHttpOutputMessage.class
│ │
│ ├─client
│ │ │ AbstractBufferingClientHttpRequest.class
│ │ │ AbstractClientHttpRequest.class
│ │ │ AbstractClientHttpRequestFactoryWrapper.class
以下略
このように、主には、コンパイルした成果物であるclassファイルが大半を占めます。
他にはxmlやpropertiesなどの設定ファイル系が内包されています。
ただし、jarファイルはzipと異なり、解凍せずにそのままの状態で使用できるメリットがあります。軽量ですみますね。
warファイル、earファイルについて
jarファイルの仲間として、warファイル、earファイルもあります。
内部的にzip圧縮なのは変わりませんが、中身に違いがあります。
WARファイルは、Webアプリを圧縮した形式です。(なので、HTMLやイメージファイル、CSSファイルなどを含む場合が多いです。)
EAR形式ファイルはJ2EEサーバー上にアプリケーションをデプロイするのに適した形式です。JAR、WARに比べると遭遇頻度はかなり低いでしょう。
リポジトリについて
さて、モジュールの実態は(基本的に)jarファイルだと上述しました。
では、そのjarファイルはいったいどこにあるのでしょうか?
それにはMavenのリポジトリについて知っておく必要があります。
Gitにはローカルリポジトリとリモートリポジトリがありますね。
Mavenにも同様な感じで、ローカルリポジトリとセントラルリポジトリがあります。
インターネット上にあるのがセントラルリポジトリ、ユーザのマシン上にあるのがローカルリポジトリです。
以下はイメージです。
セントラルリポジトリからローカルリポジトリにモジュールを取得する操作をダウンロードと呼びます。
インターネット上にあるセントラルリポジトリから、dependencyタグに書かれたモジュールをローカルリポジトリへと落としてくるわけですね。
わざわざダウンロードするためのコマンドを実行しなくてもMavenさんが自動でダウンロードしてくれます。
セントラルリポジトリの公式ページはこちら。
https://mvnrepository.com/
(※実はセントラルリポジトリからローカルリポジトリに取得するプロセスには特定の単語が使われることは少なく、人によっては「ダウンロード」とは言わない場合もあります。ここではわかりやすく「ダウンロード」とします。)
ローカルリポジトリにモジュールが存在しない場合にのみ、Mavenはセントラルリポジトリからのダウンロードを試みます。
自作したjarをローカルリポジトリにだけ格納しておき、pom.xmlのdependencyに記述することも可能です。
逆に、ローカルリポジトリからセントラルリポジトリにモジュールをアップすることを、「デプロイ」と呼びます。
さて、ローカルリポジトリはどこにあるのでしょうか?
【ローカルリポジトリの場所】
通常、C\Users\ユーザ名.m2 です。
ローカルリポジトリの場所を他に変更したい場合は、mavenの設定ファイルであるsettings.xmlを編集します。
(余談ですが、プロキシ設定を変更する場合にもsettings.xmlを編集します。プロキシを使っている環境では、その設定の記述をしないとセントラルリポジトリからダウンロードできないので。)
さて、試しにローカルリポジトリを覗いてみます。
pom.xmlに以下の記述をしたとします。
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.5</version>
<scope>test</scope>
</dependency>
すると、
repository\org\apache\poi\poi\5.2.5\poi-5.2.5.jar
というファイルが存在することがわかります。groupIdとartifactIdとversionをつなげたものがちょうどフォルダ階層になるのでわかりやすいですよね。
versionタグを記載しない場合は最新バージョンが自動的に選択されます。
(※モジュールによってはバージョン無指定が利かないこともある)
存在しないモジュール(あるいは存在しないバージョンのモジュール)を指定した場合、フォルダ自体は作成され、jarがないという状態になります。
主なMavenのコマンド
Mavenのdeployに至るまでのゴール(ライフサイクル)
mavenには様々なコマンドがありますが、前提として、mavenの「ゴール」を理解しておく必要があります。
「ゴール」とは、「工程」をイメージするとわかりやすいと思います。
※「ライフサイクルフェーズ」と表現されることもあります。
【Mavenのdeployに至るまでのゴール】※これ以外にもありますが代表的なものです。
validate
↓
compile
↓
test-compile
↓
test
↓
package
↓
install
↓
deploy
「deploy」とは先ほど上の図で説明した通り、セントラルリポジトリに上げるものですが、そこに至るまで様々な処理が実行されるわけです。
(一般的なシステム開発においては、deployまですることは少ないと思います。packageやinstall止まりでしょう。「デプロイした?」という会話があれば、それはmvn deployのことではなく、Linuxサーバやwindowsサーバへのデプロイ(jarをアップロードすること)を指すことが大半と思われます。)
そして、それぞれがmavenのコマンドとして実行可能です。
この時覚えておくべきなのは、下のゴールのコマンドを実行すると、上のゴールも実行されるということです。
下のゴールのコマンドには、上のゴールの処理が内包される。
上のゴールの実行でエラーになった場合、その時点で中断される。
例えば、deployを実行すると、validate~deployまでが実行されます。
packageを実行した場合は、validate~packageまでが実行されます。
もし、packageを実行したがtest-compileでエラーがあった場合は、その時点で中断されます。testには進みません。
では、各ゴールのコマンドはどの様なことを行うのでしょうか?
mvn validate
プロジェクトの構成が正しいかどうかを検証します。
具体的にはpom.xmlが正しくフォーマットされており、必要な情報をすべて含んでいるかどうかを確認します。
ただ、このコマンドは実務上は使うことが殆どない印象です。
mvn compile
プロダクトコード(src/main/java配下のコード)をコンパイルします。
mvn test-compile
テストコード(src/main/test配下のコード)をコンパイルします。
mvn test
テストコードを実行します。
mvn package
jarファイル(ないしはwar、earファイル)に固めます。
jar(ないしはwar、earファイル)は、targetディレクトリ配下に生成されます。
jarファイル(とか)に固めることを、パッケージングと呼びます。
mvn install
jar(war,ear)ファイルをローカルリポジトリに格納します。
mvn deploy
jar(war,ear)をセントラルリポジトリにアップします。
Mavenのそれ以外のコマンド
mvn clean
targetフォルダを削除します。
通常、mvn clean packageとか、mvn clean installというように、セットで実行します。
以前の成果物を予め削除しておいてから、packageで新規に生成する挙動になります。
これは本当に頻出です。
mvn archetype:generate
mavenプロジェクトを新規作成します。
mvn dependency:tree
プロジェクトが持つ依存関係をtreeで表示します。
出力例
[INFO] +- org.springframework.boot:spring-boot-starter-thymeleaf:jar:3.0.5:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:3.0.5:compile
[INFO] | | +- org.springframework.boot:spring-boot:jar:3.0.5:compile
[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:3.0.5:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:3.0.5:compile
[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.4.6:compile
[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.4.6:compile
[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.19.0:compile
[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:2.0.7:compile
[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:2.1.1:compile
[INFO] | | \- org.yaml:snakeyaml:jar:1.33:compile
[INFO] | \- org.thymeleaf:thymeleaf-spring6:jar:3.1.1.RELEASE:compile
[INFO] | \- org.thymeleaf:thymeleaf:jar:3.1.1.RELEASE:compile
[INFO] | +- org.attoparser:attoparser:jar:2.0.6.RELEASE:compile
[INFO] | \- org.unbescape:unbescape:jar:1.1.6.RELEASE:compile
以下略
「依存関係の解決」で記載した通り、org.springframework.boot:spring-boot-starter-thymeleafをpom.xmlに記述するだけで、示された依存関係ツリーにある他のモジュールは自動的にダウンロードされます。
mvn javadoc:javadoc
Javadocを生成します。
Javadocというのは以下の様なやつですね。
以上です。(適宜追記するかも)