# 3.5. 開発プロジェクトのビルド

## 3.5.1. 開発プロジェクトのビルド

アプリケーションサーバにデプロイするためのwarファイル、envモジュール(環境依存ファイルを格納するモジュール)のjarファイルを作成する方法を紹介する。

Maven Archetypeで作成したプロジェクトでは、warファイルを作成する方法として以下の2つの方法を提供している。

- envモジュールのjarファイルをwarファイルに含めないビルド方法 (推奨)

- envモジュールのjarファイルをwarファイルに含めるビルド方法

Note

推奨するビルド方法について

本ガイドラインでは、envモジュールのjarファイルをwarファイルに含めないビルド方法を推奨している。なお、ここで紹介するビルド方法は選択肢の一つであり、他のビルド方法を採用してもよい。

ただし、試験環境や商用環境にリリースするwarファイルとjarファイルは、EclipseなどのIDEが提供している機能を使って作成しないようにすること。

Eclipseなどの一部のIDEでは、開発用に最適化された独自のコンパイラを使ってクラスファイルを作成しており、コンパイラの違いが原因でアプリケーション実行時に予期しないエラーが発生するリスクが生まれる。

Note

プロジェクト構成の原則

原則として下記のようなプロジェクト構造とする。

1. 必ずマルチプロジェクト構成にする。

2. 一つのプロジェクトに環境依存性のある設定ファイル（ex. logback.xml, jdbc.properties）をできるだけ集約する。以降、このプロジェクトを *-env と表現する。

> - ex. secure-login-env

3. *-env以外のプロジェクトには環境依存性のある設定値を一切持たせない。

> - もちろん、src/test/resources 配下などにテスト用の環境依存性設定ファイルを格納しておくことは許可される。

4. 全てのソフトウェアのパッケージ済みバイナリをパッケージリポジトリ上に保管して管理する。

> - *.jarファイルだけではなく*.warファイルも成果物としてパッケージリポジトリにデプロイする。したがって、それらのjar/warファイルには環境依存性が含まれていてはならない。

5. *-env プロジェクトは下記のような構造にする。

> - 開発者のPC上での作業に必要な設定値をデフォルトとして src/main/resources 配下のファイルに格納する。

> - 試験サーバ、本番サーバ等、環境毎に異なる設定ファイルを src/main/resources 以外(ex. configs/test-server)のフォルダに格納し、mavenのprofile機能を使って環境毎に自動的に設定値を差し替えながら *-env-x.y.z.jarファイルをビルドする。

上記のような構造を取ることにより、ソフトウェアライフサイクルの全ての場面において、適切に開発をすることができるようになる。

1. ローカル開発環境では、プロジェクト本体と*-envプロジェクトの両方をチェックアウトし、envプロジェクトを本体プロジェクトのビルドパスに含めることによって、ローカル開発環境でのコーディングとテストを可能にする。

2. CIサーバ上ではビルドツール(maven)によるテストの実行とパッケージングを行い、必要に応じてパッケージリポジトリにartifactをdeployする。

3. 試験サーバ、本番サーバでは、パッケージリポジトリにあらかじめ保管しているプロジェクト本体に、リリース先環境にあわせてビルドした*-envプロジェクトを追加してリリースすることにより、アプリケーションの動作が可能になる。

詳細についてはチュートリアル(JavaConfig/XMLConfig)を参考にされたい。

Warning

ビルド環境について

ここではWindows環境でビルドする例になっているが、Windows環境でビルドすることを推奨しているわけではない。

本ガイドラインでは、アプリケーションの実行環境と同じOSとJDKのバージョンを使ってビルドすることを推奨する。

Mavenを使ってビルドする場合は、環境変数「JAVA_HOME」にコンパイル時に使用するJDKのホームディレクトリが指定されていることを確認されたい。
環境変数が設定されていない場合や異なるバージョンのJDKのホームディレクトリが指定されている場合は、環境変数に適切なホームディレクトリを指定すること。

[Windowsの場合]

    echo %JAVA_HOME%
    set JAVA_HOME={Please set home directory of JDK}

[Linux系の場合]

    echo $JAVA_HOME
    JAVA_HOME={Please set home directory of JDK}

Note

環境変数「JAVA_HOME」は、ビルドを実行するOSユーザーのユーザー環境変数に設定しておくとよい。

### 3.5.1.1. envモジュールのjarファイルをwarファイルに含めないビルド方法

#### 3.5.1.1.1. warファイルの作成

開発プロジェクトのルートディレクトリへ移動する。

    cd C:\work\todo

Mavenのプロファイル(`-P`パラメータ)に`warpack`を指定して、Maven installを実行する。

    mvn -P warpack clean install

Maven packageの実行が成功すると、webモジュールのtargetディレクトリの中に、envモジュールのjarファイルが含まれていないwarファイルが作成される。
(例：`C:\work\todo\todo-web\target\todo-web.war`)

Note

指定するゴールについて

上記例ではゴールに`install`を指定してwarファイルをローカルリポジトリへインストールしているが、

- warファイルの作成のみ行う場合はゴールに`package`

- Nexusなどのリモートリポジトリへデプロイする場合はゴールに`deploy`

を指定すればよい。

#### 3.5.1.1.2. envモジュールのjarファイルの作成

envモジュールのディレクトリへ移動する。

    cd C:\work\todo\todo-env

Mavenのプロファイル(`-P`パラメータ)に環境を識別するプロファイルIDを指定して、Maven packageを実行する。

    mvn -P test-server clean package

Maven packageの実行が成功すると、envモジュールのtargetディレクトリの中に、指定した環境用のjarファイルが作成される。
(例：`C:\work\todo\todo-env\target\todo-env-1.0.0-SNAPSHOT-test-server.jar`)

Note

環境を識別するプロファイルIDについて

Maven Archetypeで作成したプロジェクトでは、以下のプロファイルIDがデフォルトで定義されている。

- `local` : 開発者のローカル環境向け(IDE開発環境向け)のプロファイル (デフォルトのプロファイル)

- `test-server` : 試験環境向けのプロファイル

- `production-server` : 商用環境向けのプロファイル

デフォルトで用意しているプロファイルは上記の3つだが、開発するシステムの環境構成にあわせて追加及び修正されたい。

### 3.5.1.2. envモジュールのjarファイルをwarファイルに含めるビルド方法

#### 3.5.1.2.1. warファイルの作成

Warning

envモジュールのjarファイルをwarファイルに含める場合の注意点

envモジュールのjarファイルをwarファイルに含めた場合、warファイルを他の環境にデプロイすることができないため、間違って他の環境(特に商用環境)にデプロイされないようにwarファイルを管理すること。

また、環境毎にwarファイルを作成して各環境へリリースする方法を採用した場合、商用環境へリリースされるwarファイルが厳密にいうとテスト済みのwarファイルではないという点を意識してほしい。これは、商用環境用のwarファイルを作成する際にコンパイルをしなおすためである。

warファイルを環境毎に作成してリリースする場合は、GitやSubversionなどのVCS(Version Control System)の機能(タグ機能など)を活用し、テスト済みのソースファイルを使用して商用環境や各種テスト環境へリリースするwarファイルを作成する仕組みを確立することが特に重要である。

開発プロジェクトのルートディレクトリへ移動する。

    cd C:\work\todo

Mavenのプロファイル(`-P`パラメータ)に`warpack-with-env`とenvモジュールの中で定義している環境を識別するプロファイルIDを指定して、Maven packageを実行する。

    mvn -P warpack-with-env,test-server clean package

Maven packageの実行が成功すると、webモジュールのtargetディレクトリの中に、envモジュールのjarファイルを含んだwarファイルが作成される。
(例：`C:\work\todo\todo-web\target\todo-web.war`)

### 3.5.1.3. デプロイ

#### 3.5.1.3.1. Tomcatへのデプロイ

WebアプリケーションをTomcat上にリリースする場合は次のような手順をとる。

1. リリース対象のAPサーバ環境にあわせてmavenのprofileを指定し、 *-env プロジェクトを ビルドする。

2. 上記でビルドした*-env-x.y.z.jarファイル をあらかじめ決定したAPサーバ上のフォルダに設置する。 ex. /etc/foo/bar/abcd-env-x.y.z.jar

3. あらかじめパッケージリポジトリにデプロイ済みの*.warファイルを [CATALINA_HOME]/webapps 配下にコピーする。

4. Tomcatのリソース機能を使用して、 /etc/foo/bar/*.jar をクラスパスに追加する。

> - [CATALINA_HOME]/conf/Catalina/localhost/[contextPath].xmlファイルに下記の定義を追加する。
>   詳しくは、The Resources Componentとatrs-envのconfigsフォルダを参考されたい。

> - リソースの設定例：

>     <Resources className="org.apache.catalina.webresources.StandardRoot">
>     <PreResources className="org.apache.catalina.webresources.DirResourceSet"
>                     base="/etc/foo/bar/"
>                     internalPath="/"
>                     webAppMount="/WEB-INF/lib" />
>     </Resources>

> Note

> Catalina以外のエンジン、およびlocalhost以外のホストを利用する場合は、[contextPath].xmlを[CATALINA_HOME]/conf/[enginename]/[hostname]に配置する。

#### 3.5.1.3.2. 継続的なデプロイ

プロジェクト（ソースコードツリー）の構造、バージョン管理、インスペクションとビルド作業、ライフサイクル管理の工程を恒常的にループさせることによって目的のソフトウェアをリリースし続けることが、継続的デプロイメントである。

開発の途中では、SNAPSHOTバージョンのソフトウェアをパッケージリポジトリや開発用APサーバにリリースし、テストを実施する。
ソフトウェアを正式にリリースする場合には、バージョン番号を固定したうえでVCSのソースコードツリーに対してタグづけを行う必要がある。
このように、スナップショットリリースの場合と正式リリースの場合で、ビルドとデプロイのフローが少し異なる。

また、Webサービスを提供するAPサーバにアプリケーションをデプロイする場合には、スナップショットバージョンか正式リリースバージョンかに関わらず、デプロイ先のAPサーバ環境に合わせた環境依存性設定ファイル群と*.warファイルをセットでデプロイする必要がある。

そこで、環境依存性設定を持たない状態のライブラリ(jar,war)をmavenリポジトリに登録する作業と、それらを実際にAPサーバにデプロイする作業を分離することによって、デプロイ作業を簡潔に実施可能にする。

Note

mavenの世界では、pom.xml上の<version>タグの内容によってそれがSNAPSHOTバージョンなのかRELEASEバージョンなのかが自動的に判別される。

- 末尾が -SNAPSHOT である場合にSNAPSHOTとみなされる。例 : <version>1.0-SNAPSHOT</version>

- 末尾が -SNAPSHOT ではない場合はRELEASEとみなされる。例 : <version>1.0</version>

また、mavenパッケージリポジトリにはsnapshotsリポジトリとreleaseリポジトリの2種類があり、いくつかの制約があることに注意する。

- SNAPSHOTバージョンのソフトウェアをreleaseリポジトリに登録することはできない。その逆も不可能。

- releaseリポジトリには、同一のGAV情報を持つartifactは1回しか登録できない。（GAV=groupId,artifactId,version）

- snapshotリポジトリには、同一のGAV情報を持つartifactを何度でも登録しなおすことができる。

##### 3.5.1.3.2.1. SNAPSHOTバージョンの運用

SNAPSHOTバージョンのソフトウェアのデリバリーフローは下図のように簡潔である。

1. 開発用trunkからソースコードをチェックアウトする。

2. コンパイル、コードメトリクスの測定、テストを実行する。

> - コンパイルエラー、コードメトリクスでの一定以上のviolationの発生、テストの失敗の場合、以降の作業を中止する。

3. mavenパッケージリポジトリサーバにartifact(jar,warファイル)をアップロード(mvn deploy)する。

##### 3.5.1.3.2.2. RELEASEバージョンの運用

正式なリリースの場合、バージョン番号の付与作業が必要なため、SNAPSHOTリリースよりもやや複雑なフローとなる。

1. リリースに与えるバージョン番号を決定する。（例 : 1.0.1）

2. 開発用trunk(またはリリース用branch)からソースコードをチェックアウトする。

3. pom.xml上の<version>タグを変更する。（例 : <version>1.0.1</version>）

4. VCS上にtagを付与する。（例 : tags/1.0.1）

5. コンパイル、コードメトリクスの測定、テストを実行する。

> - コンパイルエラー、コードメトリクスでの一定以上のviolationの発生、テストの失敗の場合、以降の作業を中止する。

> - 失敗した場合はVCS上のtagを削除する。

6. mavenパッケージリポジトリサーバにartifact(jar,warファイル)をアップロード(mvn deploy)する。

Note

pom.xmlファイルの<version>タグの変更はversions-maven-pluginで可能である。

>     mvn versions:set -DnewVersion=1.0.0

上記のようなコマンドで、pom.xml内のversionタグを<version>1.0.0</version>のように編集することができる。

##### 3.5.1.3.2.3. アプリケーションサーバへのリリース

Webサービスを提供するAPサーバにアプリケーションをリリースする場合、あらかじめmavenパッケージリポジトリに登録済みのwarファイルと、リリース先のAPサーバ環境に合わせた環境依存性設定ファイル群とを、セットでリリースする。
これはスナップショットリリースか正式リリースかに関わらず同じフローとなる。

1. リリース対象バージョンのwarファイルをmavenパッケージリポジトリからダウンロードする

2. *-resourcesプロジェクト（環境依存性設定ファイルを集約しているプロジェクト）をVCSからチェックアウトする

3. mavenのprofileを機能によって、リリース先の環境に合わせた設定ファイル群で内容を差し替えてresourcesプロジェクトをパッケージし、*-resources-x.y.z.jarを生成する。

4. 生成した*-resources-x.y.z.jarファイルを、warファイル内のWEB-INF/libフォルダ配下に追加する。

> - Tomcatの場合は、*-resources-x.y.z.jarをwarファイル内部に追加するのではなく、Tomcatサーバ上の任意のパスにコピーし、そのパスをVirtualWebappLoaderの拡張クラスパスに指定する。

5. warファイルをアプリケーションサーバにデプロイする。

Note

mavenパッケージリポジトリからのwarファイルのダウンロードは、maven-dependency-pluginのcopyゴールで可能である。

>     mvn org.apache.maven.plugins:maven-dependency-plugin:3.2.0:copy^
>      -Dartifact=com.example:mywebapp:0.0.1-SNAPSHOT:war^
>      -DoutputDirectory=target

これで、targetというディレクトリ配下にmywebapp-0.0.1-SNAPSHOT.warファイルがダウンロードされる。

さらに、下記のようなコマンドで環境依存設定ファイルのパッケージをmywebapp-0.0.1-SNAPSHOT.warファイル内に追加することができる。

>     mkdir -p $WORKSPACE/target/WEB-INF/lib
>     cd $WORKSPACE/target
>     cp ./mywebapp-resources*.jar WEB-INF/lib
>     jar -ufv mywebapp-0.0.1-SNAPSHOT.war WEB-INF/lib