Maven2の紹介

Mavenは、エンタープライズJavaプロジェクトで人気のあるオープンソースのビルドツールであり、ビルドプロセスから多くのハードワークを取り除くように設計されています。Mavenは、たとえばAntや従来のmakeファイルで使用されるタスクベースのアプローチではなく、プロジェクトの構造とコンテンツが記述される宣言型アプローチを使用します。これにより、全社的な開発標準を実施し、ビルドスクリプトの作成と保守に必要な時間を短縮できます。

Maven 1で使用される宣言型のライフサイクルベースのアプローチは、多くの場合、従来のビルド手法からの根本的な逸脱であり、Maven2はこの点でさらに進んでいます。この記事では、Maven 2の背後にあるいくつかの基本的な原則を説明してから、実際の例を紹介します。Maven2の基本を確認することから始めましょう。

プロジェクトオブジェクトモデル

Maven 2プロジェクトの中心は、プロジェクトオブジェクトモデル(または略してPOM)です。これには、バージョン管理と構成管理、依存関係、アプリケーションとテストのリソース、チームメンバーと構造などに関する情報を含む、プロジェクトの詳細な説明が含まれています。POMは、プロジェクトのホームディレクトリに配置されるXMLファイル(pom.xml)の形式を取ります。簡単なpom.xmlファイルを次に示します。

 4.0.0 com.javaworld.hotels HotelDatabase war 1.0-SNAPSHOT Maven Quick Start Archetype //maven.apache.org   junit junit 3.8.1 test   

Maven2のディレクトリ構造

Mavenの力の多くは、Mavenが推奨する標準的なプラクティスから得られます。以前にMavenプロジェクトに取り組んだことがある開発者は、新しいプロジェクトの構造と構成にすぐに慣れることができます。各プロジェクトのディレクトリ構造、規則、およびカスタマイズされたAntビルドスクリプトを再発明するために時間を無駄にする必要はありません。特定の目的のために特定のディレクトリの場所を上書きすることはできますが、いくつかの理由から、標準のMaven2ディレクトリ構造を可能な限り尊重する必要があります。

  • それはあなたのPOMファイルをより小さくそしてより簡単にします
  • それはプロジェクトを理解しやすくし、あなたが去るときにプロジェクトを維持しなければならない貧しい人の生活を楽にします
  • プラグインの統合が容易になります

標準のMaven2ディレクトリ構造を図1に示します。プロジェクトのホームディレクトリには、POM(pom.xml)と2つのサブディレクトリ(すべてのソースコードのsrcと生成されたアーティファクトのターゲット)があります。

srcディレクトリにはいくつかのサブディレクトリがあり、それぞれに明確に定義された目的があります。

  • src / main / java: Javaソースコードはここにあります(奇妙なことに!)
  • src / main / resources:アプリケーションに必要なその他のリソース
  • src / main / filters:プロパティファイルの形式のリソースフィルター。実行時にのみ認識される変数を定義するために使用できます。
  • src / main / config:構成ファイル
  • src / main / webapp: WARプロジェクトのWebアプリケーションディレクトリ
  • src / test / java:ユニットテスト
  • src / test / resources:単体テストに使用されるが、デプロイされないリソース
  • src / test / filters:単体テストに使用されるリソースフィルターですが、デプロイされません
  • src / site: MavenプロジェクトのWebサイトの生成に使用されるファイル

プロジェクトのライフサイクル

プロジェクトのライフサイクルはMaven2の中心です。ほとんどの開発者は、コンパイル、テスト、デプロイなどのビルドフェーズの概念に精通しています。Antには、そのような名前のターゲットがあります。Maven 1では、対応するプラグインが直接呼び出されます。たとえば、Javaソースコードをコンパイルするjavaには、プラグインを使用します。

$maven java:compile

Maven 2では、この概念は、よく知られた、明確に定義されたライフサイクルフェーズのセットに標準化されています(図2を参照)。プラグインを呼び出す代わりに、Maven2開発者はライフサイクルフェーズを呼び出します$mvn compile

より有用なMaven2ライフサイクルフェーズのいくつかは次のとおりです。

  • generate-sources:アプリケーションに必要な追加のソースコードを生成します。これは通常、適切なプラグインを使用して実行されます。
  • compile:プロジェクトのソースコードをコンパイルします
  • test-compile:プロジェクトの単体テストをコンパイルします
  • test:src / testディレクトリでユニットテスト(通常はJUnitを使用)を実行します
  • package:コンパイルされたコードを配布可能な形式(JAR、WARなど)でパッケージ化します。
  • integration-test:必要に応じてパッケージを処理し、統合テストを実行できる環境にデプロイします
  • install:ローカルマシン上の他のプロジェクトの依存関係として使用するために、パッケージをローカルリポジトリにインストールします
  • deploy:統合またはリリース環境で実行され、他の開発者やプロジェクトと共有するために最終パッケージをリモートリポジトリにコピーします

他の多くのライフサイクルフェーズが利用可能です。詳細については、「リソース」を参照してください。

これらのフェーズは、Maven 2によって推奨される推奨プラクティスの利点を示しています。開発者がMaven 2のメインライフサイクルフェーズに慣れたら、Mavenプロジェクトのライフサイクルフェーズに安心する必要があります。

ライフサイクルフェーズでは、ジョブを実行するために必要なプラグインを呼び出します。ライフサイクルフェーズを呼び出すと、以前のライフサイクルフェーズも自動的に呼び出されます。ライフサイクルフェーズの数は限られており、理解しやすく、整理されているため、新しいMaven2プロジェクトのライフサイクルに慣れることは簡単です。

推移的な依存関係

Maven 2のハイライトの1つは、推移的な依存関係の管理です。Linuxボックスでurpmiのようなツールを使用したことがある場合は、推移的な依存関係が何であるかがわかります。Maven 1では、アプリケーションが直接的または間接的に必要とするすべてのJARを宣言する必要があります。たとえば、Hibernateアプリケーションに必要なJARを一覧表示できますか?Maven 2では、そうする必要はありません。必要なライブラリMavenに指示するだけで、Mavenがライブラリ必要なライブラリを処理します(など)。

プロジェクトでHibernateを使用するとします。dependencies次のように、pom.xmlのセクションに新しい依存関係を追加するだけです。

  hibernate hibernate 3.0.3 compile 

以上です!Hibernate 3.0.3を実行する必要がある他のJAR(およびバージョン)を知るために探し回る必要はありません。Mavenがあなたに代わってそれを行います!

Maven 2の依存関係のXML構造は、Maven 1で使用されているものと似ています。主な違いはscopeタグです。これについては、次のセクションで説明します。

依存関係のスコープ

実際のエンタープライズアプリケーションでは、デプロイされたアプリケーションにすべての依存関係を含める必要がない場合があります。一部のJARは単体テストにのみ必要ですが、その他のJARは実行時にアプリケーションサーバーによって提供されます。Maven 2では、依存関係スコープと呼ばれる手法を使用して、特定のJARを本当に必要な場合にのみ使用し、必要がない場合はクラスパスから除外します。

Mavenは、次の4つの依存関係スコープを提供します。

  • compile: A compile-scope dependency is available in all phases. This is the default value.
  • provided: A provided dependency is used to compile the application, but will not be deployed. You would use this scope when you expect the JDK or application server to provide the JAR. The servlet APIs are a good example.
  • runtime: Runtime-scope dependencies are not needed for compilation, only for execution, such as JDBC (Java Database Connectivity) drivers.
  • test: Test-scope dependencies are needed only to compile and run tests (JUnit, for example).

Project communication

An important part of any project is internal communication. While it is not a silver bullet, a centralized technical project Website can go a long way towards improving visibility within the team. With minimal effort, you can have a professional-quality project Website up and running in very little time.

This takes a whole new dimension when the Maven site generation is integrated into a build process using continuous integration or even automatic nightly builds. A typical Maven site can publish, on a daily basis:

  • General project information such as source repositories, defect tracking, team members, etc.
  • Unit test and test coverage reports
  • Automatic code reviews and with Checkstyle and PMD
  • Configuration and versioning information
  • Dependencies
  • Javadoc
  • Source code in indexed and cross-referenced HTML format
  • Team member list
  • And much more

Once again, any Maven-savvy developer will immediately know where to look to become familiar with a new Maven 2 project.

A practical example

Now that we have seen a few of the basic notions used in Maven 2, let's see how it works in the real world. The rest of this tutorial examines how we would use Maven 2 on a simple Java Enterprise Edition project. The demo application involves an imaginary (and simplified) hotel database system. To demonstrate how Maven handles dependencies between projects and components, this application will be built using two components (see Figure 3):

  • A business logic component: HotelDatabase.jar
  • A Web application component: HotelWebApp.war

You can download the source code to follow along with the tutorial in Resources.

Set up your project environment

We start by configuring your work environment. In real-world projects, you will often need to define and configure environment or user-specific parameters that should not be distributed to all users. If you are behind a firewall with a proxy, for example, you need to configure the proxy settings so that Maven can download JARs from repositories on the Web. For Maven 1 users, the build.properties and project.properties files do this job. In Maven 2, they have been replaced by a settings.xml file, which goes in the $HOME/.m2 directory. Here is an example:

     http scott tiger 8080 my.proxy.url    

Create a new project with the archetype plug-in

The next step is to create a new Maven 2 project template for the business logic component. Maven 2 provides the archetype plug-in, which builds an empty Maven 2-compatible project directory structure. This plug-in proves convenient for getting a basic project environment up and running quickly. The default archetype model will produce a JAR library project. Several other artifact types are available for other specific project types, including Web applications, Maven plug-ins, and others.

Run the following command to set up your HotelDatabase.jar project:

mvn archetype:create -DgroupId=com.javaworld.hotels - DartifactId=HotelDatabase -Dpackagename=com.javaworld.hotels

Now you have a brand new Maven 2 project directory structure. Switch to the HotelDatabase directory to continue the tutorial.

Implementing the business logic

次に、ビジネスロジックを実装します。Hotelクラスは、単純なJavaBeanです。このHotelModelクラスfindAvailableCities()は、利用可能な都市を一覧表示するfindHotelsByCity()メソッドと、特定の都市のすべてのホテルを一覧表示するメソッドの2つのサービスを実装します。HotelModelクラスの単純なメモリベースの実装を次に示します。

package com.javaworld.hotels.model;

import java.util.ArrayList; import java.util.List;

import com.javaworld.hotels.businessobjects.Hotel;

public class HotelModel {

/** * The list of all known cities in the database. */ private static String[] cities = { "Paris", "London", }; /** * The list of all hotels in the database. */ private static Hotel[] hotels = { new Hotel("Hotel Latin","Quartier latin","Paris",3), new Hotel("Hotel Etoile","Place de l'Etoile","Paris",4), new Hotel("Hotel Vendome","Place Vendome","Paris",5), new Hotel("Hotel Hilton","Trafalgar Square","London",4), new Hotel("Hotel Ibis","The City","London",3), }; /** * Returns the hotels in a given city. * @param city the name of the city * @return a list of Hotel objects */ public List findHotelsByCity(String city){ List hotelsFound = new ArrayList(); for(Hotel hotel : hotels) { if (hotel.getCity().equalsIgnoreCase(city)) { hotelsFound.add(hotel); } } return hotelsFound; } /** * Returns the list of cities in the database which have a hotel. * @return a list of city names */ public String[] findAvailableCities() { return cities; } }