Edited at

Maven 3.5のビルドライフサイクルを学ぶ


概要

Maven3のビルドライフサイクル、フェーズ、ゴールについて学んだ内容をまとめた記事です。

なお、依存関係の解決やアーティファクトのリポジトリへのインストール、プロファイルの仕組み等については扱いません。

環境


  • Windows 10 Professional

  • Java 1.8.0_144

  • Maven 3.5.2

参考


インストール

Mavenのdownloadページよりバイナリのアーカイブファイルをダウンロードし適当な場所へ展開します。

展開したディレクトリにあるbinを環境変数pathに追加します。

バージョン確認

> mvn --version

Apache Maven 3.5.2 (138edd61fd100ec658bfa2d307c43b76940a5d7d; 2017-10-18T16:58:13+09:00)
Maven home: D:\dev\apache-maven-3.5.2\bin\..
Java version: 1.8.0_144, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk1.8.0_144\jre
Default locale: ja_JP, platform encoding: MS932
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

Usage

mvn [options] [<goal(s)>] [<phase(s)>]


主な用語

Mavenの仕組みを理解するうえでよく出てくる用語についてまとめます。


ビルドライフサイクル

Maven3には下記の3つのbuilt-inビルドライフサイクルがあります。


  • default : プロジェクトのアーティファクトの作成およびデプロイ

  • clean : プロジェクトのクリーニング

  • site : プロジェクトサイトの作成およびデプロイ

それぞれのビルドライフサイクルは決められた一連のフェーズから構成されています。

たとえばcleanビルドライフサイクルは下記の3つのフェーズから構成されています。


  • pre-clean

  • clean

  • post-clean

ビルドライフサイクルがどのようなフェーズで構成されているかはcomponents.xmlで定義されていて、maven-3.5.2の場合ではmaven-core-3.5.2.jarのMETA-INF/plexus/components.xmlで確認することができます。

下記はcleanビルドライフサイクルの定義をcomponents.xmlから抜粋した内容です。

<?xml version="1.0" encoding="UTF-8"?>

<component-set>
<components>

<component>
<role>org.apache.maven.lifecycle.Lifecycle</role>
<implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
<role-hint>clean</role-hint>
<configuration>
<id>clean</id>

<phases>
<phase>pre-clean</phase>
<phase>clean</phase>
<phase>post-clean</phase>
</phases>
<default-phases>
<clean>
org.apache.maven.plugins:maven-clean-plugin:2.5:clean
</clean>
</default-phases>

</configuration>
</component>

</components>
</component-set>

ちなみにmvnコマンドの引数にビルドライフサイクルを指定して実行することはできません。

下記のmvnコマンドはcleanビルドライフサイクルを実行するという意味ではなく、cleanビルドライフサイクルのcleanフェーズを実行するように指定しています。なので実行されるのはpre-cleanとcleanフェーズでpost-cleanフェーズは実行されません。

> mvn clean

試しにdefaultビルドライフサイクル(の全体)を実行するつもりで下記のmvnコマンドを実行するとエラーになります。

> mvn default

// 省略

[ERROR] Unknown lifecycle phase "default". You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]

// 省略


フェーズ

フェーズとは、ビルドライフサイクルで実行する各工程のことです。あるフェーズを実行すると、そのフェーズのビルドライフサイクルの先頭フェーズから指定したフェーズまで順番に実行されます。

たとえばdefaultビルドライフサイクルのcompileフェーズを実行すると、defaultビルドライフサイクルの先頭フェーズであるvalidateからはじまりinitialize → generate-sources → process-sources → generate-resources → process-resources → compileの順で実行されます。

それぞれのフェーズは0個以上のゴールから構成されています。ゴールは後述しますが実態はMavenプラグインの特定の処理(を実装したJavaクラス)です。

フェーズに対してゴールが紐づけられている(以下、バインドと表記します)場合に、ゴールが実行されます。バインドの方法はいくつかありますがプラグインがデフォルトのフェーズを設定したり、pom.xmlで指定するなどの方法があります。

mvnコマンドでフェーズを指定するにはフェーズ名を指定します。

下記はcleanフェーズを実行します。

> mvn clean

フェーズはフェーズ名を半角スペースで区切って複数個指定することができます。

下記はcleanライフサイクルのcleanフェーズを実行し、続けてdefaultライフサイクルのpackageフェーズを実行します。

> mvn clean package

ゴールがバインドされていないフェーズもありますが、そのようなフェーズでは何の処理も実行されません。

たとえばdefaultビルドライフサイクルのvalidateフェーズにはデフォルトではなんのゴールもバインドされていないため、下記のmvnコマンドを実行しても何も実行されません。

> mvn validate

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building project 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.120 s
[INFO] Finished at: 2017-11-27T20:05:18+09:00
[INFO] Final Memory: 6M/276M
[INFO] ------------------------------------------------------------------------

このような、ゴールがバインドされていないフェーズはデフォルトでは意味を持っていませんが、サードパーティや自作のプラグインをバインドしてビルドライフサイクルを拡張するような使い方ができます。


コマンドラインから通常は実行しないフェーズ

pre-post-process-などのprefixが付いたフェーズは、通常コマンドラインから実行しないようですが、指定してはいけないというものでもないようです。

以下は公式ページの関連個所からの引用です。


Introduction to the Build Lifecycle

Some Phases Are Not Usually Called From the Command Line

The phases named with hyphenated-words (pre-*, post-*, or process-*) are not usually directly called from the command line. These phases sequence the build, producing intermediate results that are not useful outside the build. In the case of invoking integration-test, the environment may be left in a hanging state.



ゴール

ゴールとは、Mavenプラグインに実装されている特定の処理を実行するJavaクラスにつけられた名前です。Mavenはフェーズとこの名前を紐づけます。

1つのMavenプラグインには複数のゴールを実装することができ、1つのゴールはmaven-plugin-apiのAbstractMojoクラス(AbstractMojoはMojoインターフェースをimplementしている)を継承しています。

たとえばmaven-compiler-pluginの場合、compileとtestCompileというゴールを持っていますが、それぞれのゴールは下記のように実装されています。

MojoアノテーションのdefaultPhase属性で、そのゴールをバインドするデフォルトフェーズを指定しています。

compileゴール


CompilerMojo.java

@Mojo( name = "compile", defaultPhase = LifecyclePhase.COMPILE, threadSafe = true, 

requiresDependencyResolution = ResolutionScope.COMPILE )
public class CompilerMojo
extends AbstractCompilerMojo
{

//...省略

public void execute()
throws MojoExecutionException, CompilationFailureException
{
if ( skipMain )
{
getLog().info( "Not compiling main sources" );
return;
}

super.execute();

if ( outputDirectory.isDirectory() )
{
projectArtifact.setFile( outputDirectory );
}
}

//...省略

}


testCompileゴール


TestCompilerMojo.java

@Mojo( name = "testCompile", defaultPhase = LifecyclePhase.TEST_COMPILE, threadSafe = true,

requiresDependencyResolution = ResolutionScope.TEST )
public class TestCompilerMojo
extends AbstractCompilerMojo
{

//...省略

public void execute()
throws MojoExecutionException, CompilationFailureException
{
if ( skip )
{
getLog().info( "Not compiling test sources" );
return;
}
super.execute();
}

//...省略

}



ゴールが実行されるタイミング

ゴールが実行される状況はいくつかありますが主だったものに下記があります。


  1. フェーズにバインドされ、そのフェーズが実行された場合

  2. mvnコマンドから明示的にゴールを指定された場合


    1. 明示的に指定したゴールが依存しているフェーズが実行された場合



  3. 他のプラグインから呼び出された場合(例えばTimMoore/mojo-executorを使って)

たとえばソースコードをコンパイルするためにmaven-compiler-pluginのcompileゴールを実行したい場合は

フェーズを指定してコンパイル

compiler:compileゴールはデフォルトでcompileフェーズにバインドされているのでcompileフェーズを指定するとcompileゴールを実行します。

> mvn compile

ゴールを指定してコンパイル

このようにゴールを指定することでもcompileゴールを実行することができます。

> mvn compiler:compile

この2つの実行方法はソースコードをコンパイルするということでは同じですが、厳密に言うと実行結果が違う場合があります。

compileフェーズを実行した場合は、defaultビルドライフサイクルのvalidateフェーズからcompileフェーズまで順に実行されます。またpom.xmlでなんらかのプラグインのゴールをcompileフェーズにバインドしている場合は、そのゴールも実行されます。

compiler:compileゴールを実行した場合は、単にこのゴールの処理だけが実行されます。(後述しますが、ゴールの実装によっては、そのゴールが他のフェーズに依存している場合がありますので、そのときは依存するフェーズも実行されます)


ゴールが依存するフェーズ

ゴールを指定して直接実行する場合、そのゴールが依存しているフェーズがあれば、まずそのフェーズが実行されます。

たとえばspring-boot-maven-pluginのrunゴールは、test-compileフェーズに依存しているので、下記のように実行した場合、まずtest-compileフェーズまで実行された後に、runゴールが実行されます。

> mvn spring-boot:run

以下は公式ドキュメントからの関連個所の引用です。


spring-boot:run

Attributes:

Invokes the execution of the lifecycle phase test-compile prior to executing itself.



ゴールのスキップ

ゴールの中にはプロパティによってゴールの実行をスキップさせることができるものがあります。

ゴール
プロパティ

resources:resources
maven.resources.skip

resources:testResources
maven.test.skip

compiler:compile
maven.main.skip

compiler:testCompile
maven.test.skip

surefire:test
maven.test.skip


skipTests

failsafe:integration-test
maven.test.skip


skipITs

failsafe:verify
maven.test.skip


skipITs

install:install
maven.install.skip

deploy:deploy
maven.deploy.skip

testフェーズのスキップについて

以下のプロパティはtestフェーズに加え、integration-test、verifyフェーズをスキップします。

> mvn clean install -DskipTests

以下のプロパティはtestフェーズに加え、test-compile、integration-test、verifyフェーズをスキップします。

> mvn clean install -Dmaven.test.skip=true


プラグイン

プラグインにはMaven Projectがサポートする公式のプラグインと、それ以外(例えばサードパーティが開発するプラグインやユーザーが自作するプラグイン)に分けることができます。

公式のプラグインはAvailable Pluginsで確認することができます。

プラグインの命名には規則があり、この命名規則で公式プラグインかどうかを判別することができます。

公式のプラグインの名前は下記のルールになります。(自作のプラグインにこのルールで名前を付けてはいけません。)

maven-{plugin-name}-plugin

公式以外のプラグインの名前は下記のルールになります。

{plugin-name}-maven-plugin


補足


各ビルドライフサイクルのデフォルトのゴール


cleanビルドライフサイクル

pre-clean、post-cleanフェーズにはゴールがバインドされていないので何も実行されません。

phase
plugin
goal

pre-clean

clean
maven-clean-plugin
clean

post-clean


defaultビルドライフサイクル

defaultビルドライフサイクルでは、どのフェーズでどのゴールが実行されるかはパッケージの種類によって変わります。詳細はPlugin Bindings for default Lifecycle Referenceで確認できます。

下表はパッケージの種類がjarの場合です。

ちなみにパッケージの種類はpom.xmlのpackaging要素で定義します。明示的に定義しない場合はデフォルトとしてjarが選択されます。

phase
plugin
goal

validate

initialize

generate-sources

process-sources

generate-resources

process-resources
maven-resources-plugin
resources

compile
maven-compiler-plugin
compile

process-classes

generate-test-sources

process-test-sources

generate-test-resources

process-test-resources
maven-resources-plugin
testResources

test-compile
maven-compiler-plugin
testCompile

process-test-classes

test
maven-surefire-plugin
test

prepare-package

package
maven-jar-plugin
jar

pre-integration-test

integration-test

post-integration-test

verify

install
maven-install-plugin
install

deploy
maven-deploy-plugin
deploy


siteビルドライフサイクル

phase
plugin
goal

pre-site

site
maven-site-plugin
site

post-site

site-deploy
maven-site-plugin
deploy


Toolsプラグイン

Maven Projectがサポートするプラグインには、Toolsプラグインのようにデフォルトではビルドライフサイクルにバインドされていないプラグインがあります。このようなプラグインは特定の処理を実行するタスクとして利用します。

Toolsプラグインには以下のようなものがあります。


Maven Archetype Plugin

generateゴール

アーキタイプと呼ぶプロジェクトのテンプレートからMavenプロジェクトのひな型を生成します。

> mvn archetype:generate -B \

-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DgroupId=com.example \
-DartifactId=my-project \
-Dversion=1.0-SNAPSHOT

Mavenプラグインのプロジェクトのひな型を生成するにはrchetypeArtifactIdにmaven-archetype-pluginを指定します。

> mvn archetype:generate -B \

-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-plugin \
-DgroupId=com.example \
-DartifactId=my-maven-plugin \
-Dversion=1.0-SNAPSHOT


Maven Dependency Plugin

treeゴール

プロジェクトの依存関係をツリー表示します。

> mvn dependency:tree

結果をファイルに保存するにはoutputFileでファイル名を指定します。

このファイルをバージョン管理することで依存関係の変化を把握しやすくなります。

> mvn dependency:tree -DoutputFile=dependecy.txt

ビルド時に自動的に出力させるにはライフサイクルに組み込みます。

<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>tree</id>
<phase>compile</phase>
<goals>
<goal>tree</goal>
</goals>
<configuration>
<outputFile>dependency.txt</outputFile>
</configuration>
</execution>
</executions>
</plugin>


Maven Help Plugin

effective-pomゴール

デフォルトの設定を含めたpom.xmlの内容を表示します。

> mvn help:effective-pom

systemゴール

環境変数やシステムプロパティを表示します。

> mvn help:system

describeゴール

pluginプロパティで指定するプラグインのhelpメッセージを表示します。

> mvn help:describe -Dplugin=compiler

より詳細な情報を得るにはdetailプロパティを指定します。

> mvn help:describe -Dplugin=compiler -Ddetail

cmdプロパティにフェーズを指定するとそのフェーズを含むビルドライフサイクルの各フェーズにバインドされているプラグインを調べることができます。

> mvn help:describe -Dcmd=package

[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building my-project 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-help-plugin:2.2:describe (default-cli) @ my-project ---
[INFO] 'package' is a phase corresponding to this plugin:
org.apache.maven.plugins:maven-jar-plugin:2.4:jar

It is a part of the lifecycle for the POM packaging 'jar'. This lifecycle includes the following phases:
* validate: Not defined
* initialize: Not defined
* generate-sources: Not defined
* process-sources: Not defined
* generate-resources: Not defined
* process-resources: org.apache.maven.plugins:maven-resources-plugin:2.6:resources
* compile: org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
* process-classes: Not defined
* generate-test-sources: Not defined
* process-test-sources: Not defined
* generate-test-resources: Not defined
* process-test-resources: org.apache.maven.plugins:maven-resources-plugin:2.6:testResources
* test-compile: org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile
* process-test-classes: Not defined
* test: org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
* prepare-package: Not defined
* package: org.apache.maven.plugins:maven-jar-plugin:2.4:jar
* pre-integration-test: Not defined
* integration-test: Not defined
* post-integration-test: Not defined
* verify: Not defined
* install: org.apache.maven.plugins:maven-install-plugin:2.4:install
* deploy: org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.147 s
[INFO] Finished at: 2017-12-03T13:34:00+09:00
[INFO] Final Memory: 11M/276M
[INFO] ------------------------------------------------------------------------

それぞれのプラグインでhelpゴールを実行することで同様のhelpメッセージが取得できます。

> mvn compiler:help


サードパーティのプラグイン


MojoHaus Maven Plugins Project

たくさんのプラグインを公開しているプロジェクトです。Codehasが2015年で運営を停止したため、MojaHausはそれを引き継ぐ形で発足しました。(詳しくはThe Demise of Open Source Hosting Providers Codehaus and Google Codeをご覧ください)

メジャーなプラグインではFindBugs Maven Pluginがあります。


Spring Boot Maven Plugin

spring-projects/spring-boot

Spring Bootアプリケーションで使用するプラグインです。

Goals

Goal
Binds by default to the lifecycle phase

run
validate

repackage
package

start
pre-integration-test

stop
post-integration-test

build-info
generate-resources

runゴール

spring bootアプリケーションを実行します。

> mvn spring-boot:run

プロファイルを指定するにはrun.profilesパラメータを使用します。

> mvn spring-boot:run -Drun.profiles=dev,test

なお、Spring Boot 2.0以降は下記のようになる予定です。(記2018/2/10)

> mvn spring-boot:run -Dspring-boot.run.profiles=dev,test

build-infoゴール

ビルド情報をtarget/classes/META-INF/build-info.propertiesに出力します。この情報はspring-boot-actuatorから参照されます。

プロパティファイルにどのような情報を出力するかはカスタマイズ可能です。

このゴールはデフォルトで、defaultビルドライフサイクルのgenerate-resourcesフェーズにバインドされています。

デフォルトでは以下の情報が出力されます。

#Properties

#Fri Dec 01 14:01:25 JST 2017
build.time=2017-12-01T14\:01\:25+0900
build.artifact=singleds
build.group=com.example
build.name=singleds
build.version=0.0.1-SNAPSHOT

spring-boot-actuatorを有効にしていなくてもClass BuildPropertiesを介して取得できます。

@Autowired

private BuildProperties prop;


Dependency-check-maven Plugin

脆弱性を持つ依存関係があるかチェックしてくれるプラグインです。

Goals

Goal
Binds by default to the lifecycle phase

aggregate

check

update-only

purge

checkゴール

プロジェクトが依存するライブラリに脆弱性があるか検査します。

> mvn dependency-check:check


Tips集

参考になったtips。