第3章 クラスローディングとモジュール
3.1. はじめに
3.1.1. クラスロードとモジュールの概要
JBoss EAP 6 は、デプロイされたアプリケーションのクラスパスを制御するために新しいモジュール形式のクラスローディングシステムを使用します。このシステムは、階層クラスローダーの従来のシステムよりも、柔軟性があり、より詳細に制御できます。開発者は、アプリケーションで利用可能なクラスに対して粒度の細かい制御を行い、アプリケーションサーバーで提供されるクラスを無視して独自のクラスを使用するようデプロイメントを設定できます。
モジュール形式のクラスローダーにより、すべての Java クラスはモジュールと呼ばれる論理グループに分けられます。各モジュールは、独自のクラスパスに追加されたモジュールからクラスを取得するために、他のモジュールの依存関係を定義できます。デプロイされた各 JAR および WAR ファイルはモジュールとして扱われるため、開発者はモジュール設定をアプリケーションに追加してアプリケーションのクラスパスの内容を制御できます。
3.1.2. クラスの読み込み
クラスローディングは、Java クラスとリソースが Java ランタイム環境にロードされるメカニズムです。
3.1.3. モジュール
モジュールは、クラスローディングおよび依存関係管理に使用されるクラスの論理グループです。JBoss EAP 6 は、静的モジュールと動的モジュールと呼ばれることもある 2 つの異なるタイプのモジュールを識別します。ただし、2 つの違いは、パッケージ方法だけです。
- 静的モジュール
- 静的モジュールは、アプリケーションサーバーの
EAP_HOME/modules/
ディレクトリーで事前定義されます。各サブディレクトリーは 1 つのモジュールを表し、設定ファイル (module.xml
) と必要な JAR ファイルを含むmain/
サブディレクトリーを定義します。モジュールの名前は、module.xml
ファイルで定義されています。アプリケーションサーバーが提供するすべての API は、Java EE API や JBoss Logging などの他の API を含む静的モジュールとして提供されます。例3.1 module.xml ファイルの例
<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="com.mysql"> <resources> <resource-root path="mysql-connector-java-5.1.15.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
モジュール名、com.mysql
、main/
サブディレクトリー名を除いて、モジュールのディレクトリー構造と一致する必要があります。JBoss EAP ディストリビューションで提供されるモジュールは、EAP_HOME/modules
ディレクトリー内のsystem
ディレクトリーにあります。このため、サードパーティーによって提供されるモジュールから分離されます。JBoss EAP 6.1 以降の上にレイヤー化された Red Hat が提供するレイヤード製品も、system
ディレクトリー内にモジュールをインストールします。カスタム静的モジュールの作成は、同じサードパーティーライブラリーを使用する同じサーバー上に多くのアプリケーションがデプロイされる場合に役立ちます。これらのライブラリーを各アプリケーションとバンドルする代わりに、JBoss 管理者はこれらのライブラリーが含まれるモジュールを作成およびインストールできます。アプリケーションは、カスタム静的モジュールで明示的な依存関係を宣言できます。モジュールレイアウトごとに 1 つのディレクトリーを使用して、カスタムモジュールがEAP_HOME/modules
ディレクトリーにインストールされるようにする必要があります。こうすると、同梱されたバージョンではなく、system
ディレクトリーに存在するカスタムバージョンのモジュールがロードされるようになります。これにより、ユーザー提供のモジュールがシステムモジュールよりも優先されます。JBOSS_MODULEPATH
環境変数を使用して JBoss EAP がモジュールを検索する場所を変更する場合は、指定された場所の 1 つでsystem
サブディレクトリー構造を探します。システム
構造体は、JBOSS_MODULEPATH
で指定された場所のどこかに存在する必要があります。 - 動的モジュール
- 動的モジュールは、各 JAR または WAR デプロイメント (または、EAR 内のサブデプロイメント) に対してアプリケーションサーバーによって作成およびロードされます。動的モジュールの名前は、デプロイされたアーカイブの名前に由来します。デプロイメントはモジュールとしてロードされるため、依存関係を設定し、他のデプロイメントで依存関係として使用することが可能です。
モジュールは必要な場合にのみロードされます。通常、モジュールは、明示的または暗黙的な依存関係があるアプリケーションがデプロイされる場合にのみロードされます。
3.1.4. モジュールの依存性
モジュールの依存関係は、あるモジュールが機能するために別のモジュールのクラスを必要とするという宣言です。モジュールは、他の任意の数のモジュールへの依存関係を宣言できます。アプリケーションサーバーがモジュールをロードすると、モジュラークラスローダーはそのモジュールの依存関係を解析し、各依存関係からクラスをクラスパスに追加します。指定の依存関係が見つからない場合、モジュールはロードできません。
デプロイされたアプリケーション (JAR または WAR) は動的モジュールとしてロードされ、依存関係を利用して JBoss EAP 6 によって提供される API にアクセスします。
依存関係には明示的と暗黙的の 2 つのタイプがあります。
明示的な依存関係
明示的な依存関係は開発者が設定ファイルで宣言します。静的モジュールは、module.xml
ファイルで依存関係を宣言できます。動的モジュールは、デプロイメントの MANIFEST.MF
または jboss-deployment-structure.xml
デプロイメント記述子で宣言された依存関係を持つことができます。
明示的な依存関係は、オプションとして指定できます。オプションの依存関係をロードできなくても、モジュールのロードは失敗しません。ただし、依存関係は後で使用できるようになっても、モジュールのクラスパスには追加されません。依存関係はモジュールがロードされるときに利用可能である必要があります。
暗黙的な依存関係
デプロイメントで特定の条件またはメタデータが検出されると、アプリケーションサーバーによって暗黙の依存関係が自動的に追加されます。JBoss EAP 6 に同梱される Java EE 6 API は、デプロイメントで暗黙的な依存関係が検出されたときに追加されるモジュールの例になります。
デプロイメントは、特定の暗黙の依存関係を除外するように設定することもできます。これは、
jboss-deployment-structure.xml
デプロイメント記述子ファイルを使用して行われます。これは通常、アプリケーションサーバーが暗黙的な依存関係として追加しようとする特定のバージョンのライブラリーをアプリケーションがバンドルする場合に行われます。
モジュールのクラスパスには独自のクラスとその直接の依存関係のクラスのみが含まれます。モジュールは 1 つの依存関係の依存関係クラスにはアクセスできませんが、暗黙的な依存関係のエクスポートを指定できます。ただし、モジュールは、明示的な依存関係をエクスポートするように指定できます。エクスポートした依存関係は、エクスポートするモジュールに依存するモジュールに提供されます。
例3.2 モジュールの依存関係
モジュール A はモジュール B に依存し、モジュール B はモジュール C に依存します。モジュール A はモジュール B のクラスにアクセスでき、モジュール B はモジュール C のクラスにアクセスできます。以下の場合を除き、モジュール A はモジュール C のクラスにはアクセスできません。
- モジュール A がモジュール C への明示的な依存関係を宣言する場合。
- または、モジュール B がモジュール B の依存関係をモジュール C でエクスポートする場合。
3.1.5. デプロイメントでのクラスローディング
クラスのロードの目的で、すべてのデプロイメントは JBoss EAP 6 によってモジュールとして扱われます。このようなデプロイメントは動的モジュールと呼ばれます。クラスローディングの動作はデプロイメントの種類によって異なります。
- WAR デプロイメント
- WAR デプロイメントは 1 つのモジュールとして考慮されます。
WEB-INF/lib
ディレクトリーのクラスはWEB-INF/classes
ディレクトリーにあるクラスと同じように処理されます。WAR にパッケージされているクラスはすべて、同じクラスローダーでロードされます。 - EAR デプロイメント
- EAR デプロイメントは、複数のモジュールで設定されています。これらのモジュールの定義は、次のルールに従います。
- EAR の
lib/
ディレクトリーは親モジュールと呼ばれる 1 つのモジュールです。 - また、EAR 内の各 WAR デプロイメントは 1 つのモジュールです。
- 同様に、EAR 内の EJB JAR デプロイメントも 1 つのモジュールです。
サブデプロイメントモジュール (EAR 内の WAR および JAR デプロイメント) は、自動的に親モジュールに依存しますが、サブデプロイメントモジュール同士が自動的に依存するわけではありません。ただし、相互で自動的な依存関係はありません。これはサブデプロイメントの分離と呼ばれ、デプロイメントごとに、またはアプリケーションサーバー全体に対して無効にすることができます。サブデプロイメントモジュール間の明示的な依存関係は、他のモジュールと同じ方法で追加することが可能です。
3.1.6. クラスローディングの優先順位
JBoss EAP 6 のモジュール形式クラスローダーは、優先順位を決定してクラスローディングの競合が発生しないようにします。
デプロイメントに、パッケージとクラスの完全なリストがデプロイメントごとおよび依存関係ごとに作成されます。このリストは、クラスローディングの優先順位のルールに従って順序付けされます。実行時にクラスをロードすると、クラスローダーはこのリストを検索し、最初に一致したものをロードします。こうすることで、デプロイメントクラスパス内の同じクラスやパッケージの複数のコピーが競合しないようになります。
クラスローダーは上から順にクラスをロードします。
- 暗黙的な依存関係これらは、JAVA EE API などの JBoss EAP 6 によって自動的に追加される依存関係です。これらの依存関係には一般的な機能や JBoss EAP 6 によって提供される API が含まれるため、これらの依存関係のクラスローダー優先順位は最も高くなります。各暗黙的依存関係の詳細は、「暗黙的なモジュール依存関係」を参照してください。
- 明示的な依存関係これらは、アプリケーション設定に手動で追加される依存関係です。これは、アプリケーションの
MANIFEST.MF
ファイルまたは新しいオプションの JBoss デプロイメント記述子jboss-deployment-structure.xml
ファイルを使用して実行できます。明示的に依存関係を追加する方法は、「デプロイメントへの明示的なモジュール依存関係の追加」を参照してください。 - ローカルリソースデプロイメント自体の内部にパッケージ化されたクラスファイル。たとえば、WAR ファイルの
WEB-INF/classes
またはWEB-INF/lib
ディレクトリーにあるものです。 - デプロイメント間の依存関係これらは、EAR デプロイメント内の他のデプロイメントへの依存関係です。これには、EAR の
lib
ディレクトリーにあるクラスや他の EJB jar で定義されたクラスが含まれることがあります。
3.1.7. 動的モジュールの名前付け
すべてのデプロイメントは JBoss EAP 6 によってモジュールとしてロードされ、以下の慣例に従って名前が付けられます。
- WAR および JAR ファイルのデプロイメントは次の形式で名前が付けられます。
deployment.DEPLOYMENT_NAME
例えば、inventory.war
とstore.jar
は、それぞれdeployment.inventory.war
とdeployment.store.jar
というモジュール名を持ちます。 - エンタープライズアーカイブ内のサブデプロイメントは次の形式で名前が付けられます。
deployment.EAR_NAME.SUBDEPLOYMENT_NAME
たとえば、エンタープライズアーカイブaccounts.ear
内のreports.war
のサブデプロイメントには、deployment.accounts.ear.reports.war
というモジュール名が付きます。
3.1.8. jboss-deployment-structure.xml
jboss-deployment-structure.xml
は JBoss EAP 6 の新しい任意のデプロイメント記述子です。このデプロイメント記述子を使用すると、デプロイメントでクラスローディングを制御できます。
このデプロイメント記述子の XML スキーマは
EAP_HOME/docs/schema/jboss-deployment-structure-1_2.xsd
にあります。