こんにちは、サイオステクノロジー武井です。今回は、Mavenについて書こうとおもっております。でもMavenの細かい話は抜きにして、なんでそんなもん必要なのっていうところに重点を置いて、書きたいと思います。
gradleとかもありますが、未だにまだMavenって現役ですよね?っておもっていますので、きっとこの記事が誰かの役に立つと思います。
Mavenって?
Javaのソースコードのコンパイルやビルドの手順を簡単にしてくれて、さらにライブラリの依存性を解決した上で、中央集権的に管理されたリポジトリからライブラリを簡単に取得出来るツールです。
Mavenを使わないとどうなるか?
先の説明では、少々、というか全然わからないと思います。私も初めてMavenを学んだときは、Mavenの使い方が書いてある本や記事はあったのですが、そもそもその必要性がよくわかりませんでした。そこから説明してほしかったなーと思います。
ということで、まずはMavenを使わないでいろんなことをしてみたいと思います。
簡単なハロワを実行
まずは簡単なハロワ(Hello Worldと表示するプログラム)を作ってみます。
今回作成するハロワのディレクトリ構成とファイル群は下記のとおりです。
com └── example └── demo ├── HelloWorld.java └── Person.java
上記のソースコードの詳細は以下の通りです。
package com.example.demo; // 人を表すクラス public class Person { // 人の名前 private String name; // コンストラクタで人の名前を渡す public Person(String name) { this.name = name; } // 名前を取得するメソッドを定義する public String getName() { return this.name; } }
package com.example.demo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HelloWorld { public static void main(String[] args) { // Personクラスからインスタンスを生成し、その際コンストラクタの引数で名前を渡す Person person = new Person("ntakei"); // 「Hello World!![人の名前]」と表示する。 System.out.println("Hello World!! " + person.getName()); } }
これを実行するためには、コンパイルが必要です。ということでコンパイルします。Person.classとHelloWorld.classの2つのファイルが出来上がります。
$ javac com/example/demo/HelloWorld.java
実行します。
$ java com/example/demo/HelloWorld Hello World!! ntakei
手順をまとめると以下のような感じです。
- コンパイルする。
- 実行する
なかなかにめんどくさいですね。
簡単なハロワをjarにする
さて、先のハロワですが、他の環境で実行したいときに、わざわざPerson.classとHelloWorld.classの2つのファイルを持ち歩くのは面倒です。そこで、Javaにはjarという仕組みがあって、複数のクラスやその実行に必要な設定ファイルなどを一つのファイルにすることが出来ます。
ということで先程のハロワをコンパイルからやり直してみましょう。ということでコンパイルします。Person.classとHelloWorld.classの2つのファイルが出来上がります。
$ javac com/example/demo/HelloWorld.java
jarにします。tarコマンドとインターフェースが非常に似ています。同じディレクトリにhelloworld.jarというファイルが出来上がっているはずです。
$ jar cvf helloworld.jar . $ ls com helloworld.jar
jarからプログラムを実行してみましょう。
$ java -cp helloworld.jar com.example.demo.HelloWorld Hello World!! ntakei
手順をまとめると以下のような感じです。
- コンパイルする
- jarにする
- 実行する
だんだん手順が増えてめんどくさくなりました。つらみー。
ログを出力出来るようにする
ハロワに簡単なログを出力出来るようにしましょう。そのためにはslf4jライブラリが必要になります。https://www.slf4j.org/のサイトから以下の2つをダウンロードします(バージョンは2021年6月21日時点での最新です)。
- slf4j-api-1.7.9.jar
- slf4j-simple-1.7.30.jar
そしてそのライブラリを以下のように配置します。
com └── example └── demo ├── HelloWorld.java └── Person.java slf4j-api-1.7.9.jar slf4j-simple-1.7.30.jar
HelloWorld.javaを以下のように修正します。
package com.example.demo; // slf4jのライブラリをインポートする import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HelloWorld { public static void main(String[] args) { // ログ出力のための準備をする Logger logger = LoggerFactory.getLogger("testlogger"); // ログ出力!! logger.info("hogefugapiyo"); Person person = new Person("ntakei"); System.out.println("Hello World!! " + person.getName()); } }
コンパイルします。先程のslf4jライブラリを指定する必要があります。
$ javac -cp .:slf4j-api-1.7.9.jar:slf4j-simple-1.7.30.jar com/example/demo/HelloWorld.java
jarにします。
$ jar cvf helloworld.jar .
実行します。
$ java -cp helloworld.jar:slf4j-api-1.7.9.jar:slf4j-simple-1.7.30.jar com/example/demo/HelloWorld [main] INFO logger - hogefugapiyo Hello World!! ntakei
手順をまとめると以下のような感じです。
- ライブラリをダウンロードする。
- コンパイルする
- jarにする
- 実行する
もうつらい。
Mavenを使うとどうなるか?
ヽ(=´▽`=)ノ
Mavenは、今までMavenを使わない場合に実行してきた「ライブラリをダウンロードする」「コンパイルする」「jarにする」あたりを全部勝手にやってくれます。そういうツールなのです。ただし、Mavenの色々なお作法に従う必要があります。
お作法その1としては、ディレクトリ構成です。ということで、先に実行したハロワログ出力jar実行バージョンをMavenのお作法に合わせた構成にすると以下のようになります。
. ├── pom.xml → Mavenの挙動を定義したファイルです。 └── src ├── main │ └── java → ソースコードを格納するディレクトリです。 │ └── com │ └── example │ └── demo │ ├── HelloWorld.java │ └── Person.java └── test └── java → テストコードを格納するディレクトリです。今回は使いません。 └── com └── example └── demo └── AppTest.java
お作法その2としてはpom.xmlを書かなければいけないこととその書き方です。詳細は書籍とかを参照していただくとして、本記事ではその概要を説明します。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- このハロワのプログラムのグループID(会社名など)とアーティファクトID(プログラムの一意の名称)を定義する --> <groupId>com.example</groupId> <artifactId>HelloWorld</artifactId> <version>1.0-SNAPSHOT</version> <name>HelloWorld</name> <!-- Javaのコンパイル時のバージョンなどを定義する --> <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> <!-- 利用するライブラリを定義する。ここで定義すると勝手にMavenのリポジトリからダウンロードしてきてくれる --> <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies> <!-- jarの作り方などを定義する --> <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>3.3.0</version> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> </plugins> </build> </project>
ではライブラリのダウンロード、コンパイル、jarの作成までやってみます。
$ mvn clean package
すると、targetディレクトリ配下に以下のファイルが出来ていると思います。これらの中のHelloWorld-1.0-SNAPSHOT-jar-with-dependencies.jarというのが成果物です。
$ ls target/ HelloWorld-1.0-SNAPSHOT-jar-with-dependencies.jar generated-sources surefire-reports HelloWorld-1.0-SNAPSHOT.jar generated-test-sources test-classes archive-tmp maven-archiver classes maven-status
実行してみましょう。
$ java -cp target/HelloWorld-1.0-SNAPSHOT-jar-with-dependencies.jar com.example.demo.HelloWorld [main] INFO testlogger - hogefugapiyo Hello World!! ntakei
あら、これだけ?
以下の手順になりました。あの複雑だった手順がマジシンプルに!!
- mavenでビルドする。
- 実行する。
まとめ
Mavenのお作法に従ったディレクトリ構成にソースを置いて、pom.xmlを定義するだけで、ビルドやライブラリのダウンロードなど面倒なことを全てやってくれるのです。とっても便利ですね。