第3章 クラスローディングとモジュール

3.1. はじめに

3.1.1. クラスロードとモジュールの概要

JBoss Enterprise Application Platform 6 は、デプロイされたアプリケーションのクラスパスを制御するために新しいモジュール形式のクラスロードシステムを使用します。このシステムでは、階層クラスローダーの従来のシステムよりも、柔軟性と制御が強化されています。開発者は、アプリケーションで利用可能なクラスに対して粒度の細かい制御を行い、アプリケーションサーバーで提供されるクラスを無視して独自のクラスを使用してデプロイメントを設定できます。
モジュール形式のクラスローダーは、すべての Java クラスをモジュールと呼ばれる論理グループに分けます。各モジュールは、独自のクラスパスに追加されたモジュールからのクラスを取得するために、他のモジュールの依存関係を定義できます。このシステムは、アプリケーションサーバーでパッケージ化された API からのすべての Java クラスと、デプロイされたアプリケーションの Java クラスに適用されます。
デプロイされた各 JAR および WAR ファイルはモジュールとして扱われるため、開発者は、モジュール設定と依存関係を追加することにより、アプリケーションのクラスパスの内容を制御できます。次の資料では、JBoss Enterprise Application Platform 6 でアプリケーションを正しく構築およびデプロイするために開発者が知る必要があることが説明されています。

3.1.2. クラスローディング

クラスローディングとは、Java クラスやリソースを Java ランタイム環境にロードするメカニズムのことです。

3.1.3. モジュール

モジュールは、クラスロードと依存関係管理のために使用されるクラスの論理的なグループです。JBoss Enterprise Application Platform 6 では、静的モジュールと動的モジュールの 2 種類のモジュールが存在します。ただし、この 2 種類のモジュールの違いは、パッケージ化の方法のみです。すべてのモジュールは同じ機能を提供します。
静的モジュール
静的モジュールは、アプリケーションサーバーの EAP_HOME/modules/ ディレクトリで事前に定義されます。各サブディレクトリは 1 つのモジュールを表し、1 つまたは複数の JAR ファイルと設定ファイル (modules.xml) が含まれます。モジュールの名前は、module.xml ファイルで定義されます。アプリケーションサーバーで提供されるすべての API (Java EE API や JBoss Logging などの他の API を含む) は、静的モジュールとして提供されます。
カスタム静的モジュールの作成は、同じサードパーティーライブラリを使用する同じサーバー上に多くのアプリケーションがデプロイされる場合に役立ちます。これらのライブラリを各アプリケーションとバンドルする代わりに、JBoss 管理者はこれらのライブラリが含まれるモジュールを作成およびインストールすることができます。これらのアプリケーションはカスタム静的モジュールで明示的な依存関係を宣言できます。
動的モジュール
動的モジュールは、各 JAR または WAR デプロイメント (または、EAR 内のサブデプロイメント) に対してアプリケーションサーバーによって作成およびロードされます。動的モジュールの名前は、デプロイされたアーカイブの名前から派生されます。デプロイメントはモジュールとしてロードされるため、依存関係を設定でき、他のデプロイメントは依存関係として使用することが可能です。
モジュールは必要な時のみロードされます。通常、明示的または暗黙的な依存関係があるアプリケーションがデプロイされる場合にのみ実行されます。

3.1.4. モジュールの依存関係

モジュール依存関係とは、あるモジュールが機能するには別のモジュールのクラスを必要とする宣言のことです。モジュールはいくつでも他のモジュールの依存関係を宣言することができます。アプリケーションサーバーがモジュールをロードする時、モジュールクラスローダーがモジュールの依存関係を解析し、各依存関係のクラスをクラスパスに追加します。指定の依存関係が見つからない場合、モジュールはロードできません。
デプロイされたアプリケーション (JAR および WAR) は動的モジュールとしてロードされ、依存関係を用いて JBoss Enterprise Application Platform 6 によって提供される API へアクセスします。
依存関係には明示的と暗黙的の 2 つのタイプがあります。
明示的な依存関係は開発者によって設定に宣言されます。静的モジュールは依存関係を modules.xml ファイルに宣言することができます。動的モジュールはデプロイメントの MANIFEST.MF または jboss-deployment-structure.xml 記述子に依存関係を宣言することができます。
暗示的な依存関係は任意として指定することができます。任意の依存関係をロードできなくても、モジュールのロードに失敗する原因にはなりません。しかし、依存関係が後で使用できるようになっても、モジュールのクラスパスには追加されません。モジュールがロードされる時に依存関係が使用できなければなりません。
暗黙的な依存関係は、特定の条件やメタデータがデプロイメントで見つかった場合に自動的に追加されます。JBoss Enterprise Application Platform に含まれる Java EE 6 API は、デプロイメントに暗黙的な依存関係が検出された時に追加されるモジュールの例になります。
デプロイメントを設定して特定の暗黙的な依存関係を除外することも可能です。この設定は jboss-deployment-structure.xml デプロイメント記述子ファイルで行います。これは、アプリケーションサーバーが暗黙的な依存関係として追加しようとする特定バージョンのライブラリをアプリケーションがバンドルする場合に一般的に用いられます。
モジュールのクラスパスには独自のクラスとその直接の依存関係のみが含まれます。モジュールは 1 つの依存関係の依存関係クラスにはアクセスできませんが、暗示的な依存関係がエクスポートされたことを指定することができます。エクスポートされた依存関係は、エクスポートするモジュールに依存するモジュールへ提供されます。

例3.1 モジュールの依存関係

モジュール A はモジュール B に依存し、モジュール B はモジュール C に依存します。モジュール A はモジュール B のクラスにアクセスでき、モジュール B はモジュール C のクラスにアクセスできます。以下の場合を除き、モジュール A はモジュール C のクラスにはアクセスできません。
  • モジュール A がモジュール C への明示的な依存関係を宣言する場合。
  • または、モジュール B がモジュール B の依存関係をモジュール C でエクスポートする場合。

3.1.5. デプロイメントでのクラスローディング

JBoss Enterprise Application Platform では、クラスローディングのためにデプロイメントはすべてモジュールとして処理されます。このようなデプロイメントは動的モジュールと呼ばれます。クラスローディングの動作はデプロイメントのタイプによって異なります。
WAR デプロイメント
WAR デプロイメントは 1 つのモジュールとして考慮されます。WEB-INF/lib ディレクトリのクラスは WEB-INF/classes ディレクトリにあるクラスと同じように処理されます。war にパッケージされているクラスはすべて、同じクラスローダーでロードされます。
EAR デプロイメント
EAR デプロイメントは複数のモジュールで構成されます。これらのモジュールは以下のルールに従って定義されます。
  1. EAR の lib/ ディレクトリは親モジュールと呼ばれる1つのモジュールです。
  2. また、EAR 内の各 WAR デプロイメントは1つのモジュールです。
  3. 同様に、EAR 内の EJB JAR デプロイメントも 1 つのモジュールとなっています。
サブデプロイメントモジュール (EAR 内の WAR、JAR デプロイメント) は、自動的に親モジュールに依存しますが、サブデプロイメント同士が自動的に依存するわけではありません。これは、サブデプロイメントの分離 (subdeployment isolation) と呼ばれ、デプロイメントごとまたはアプリケーションサーバー全体で無効にすることができます。
サブデプロイメントモジュール間の明示的な依存関係については、他のモジュールと同じ方法で追加することが可能です。

3.1.6. クラスローディングの優先順位

JBoss Enterprise Application Platform 6 のモジュラークラスローダーは優先順位の仕組みを利用してクラスローディングの競合が発生しないようにします。
デプロイメント時に、パッケージとクラスの完全リストがデプロイメント毎そして依存性毎に作成されます。この一覧は、クラスローディングの優先順位のルールに従い順番に並べられています。ランタイムにクラスをロードすると、クラスローダーはこの一覧を検索し最初に一致したものをロードします。こうすることで、デプロイメントクラスパスにある同じクラスやパッケージの複数のコピーが競合しないようにします。
クラスローダーは上から順に(降順) クラスをロードします。
  1. 暗黙的な依存性
    Java EE API などの、JBoss Enterprise Application Platform 6 が自動的に追加する依存性です。こちらの依存性は、一般的な機能や JBoss Enterprise Application Platform 6 が対応する API が含まれているため、優先順位が最も高くなっています。
    各暗黙的依存性に関する完全な詳細情報は 「暗黙的なモジュール依存関係」 を参照してください。
  2. 明示的な依存性
    アプリケーション設定にて手動で追加される依存性です。これらの依存性は、アプリケーションの MANIFEST.MF ファイルや、新しくオプションで追加された JBoss の配備記述子 jboss-deployment-structure.xml ファイルを使い追加可能です。
    明示的な依存性の追加方法については、「デプロイメントへの明示的なモジュール依存関係の追加」 を参照してください。
  3. ローカルリソース
    デプロイメント内にパッケージ化されるクラスファイル (例:WAR ファイルの WEB-INF/classes あるいは WEB-INF/lib から)
  4. デプロイメント間の依存性
    EAR デプロイメントにある他のデプロイメントとの依存性のことです。これには、EAR の lib ディレクトリにあるクラスや他の EJB jar に定義されているクラスが含まれることがあります。

3.1.7. 動的モジュールの名前付け

すべてのモジュールは JBoss Enterprise Application Platform 6 によってモジュールとしてロードされ、以下の慣例に従って名前が付けられます。
  1. WAR および JAR ファイルのデプロイメントは次の形式で名前が付けられます。
    deployment.DEPLOYMENT_NAME 
    例えば、inventory.war のモジュール名は deployment.inventory.war となり、store.jar のモジュール名は deployment.store.jar となります。
  2. エンタープライズアーカイブ内のサブデプロイメントは次の形式で名前が付けられます。
    deployment.EAR_NAME.SUBDEPLOYMENT_NAME 
    例えば、エンタープライズアーカイブ accounts.ear 内にある reports.war のサブデプロイメントのモジュール名は deployment.accounting.ear.reports.war になります。

3.1.8. Jboss-deployment-structure.xml

jboss-deployment-structure.xml は JBoss Enterprise Application Platform 6 の新しい任意のデプロイメント記述子です。このデプロイメント記述子はデプロイメントのクラスローディングを制御できるようにします。
このデプロイメント記述子の XML スキーマは EAP_HOME/docs/schema/jboss-deployment-structure-1_0.xsd にあります。