この章の内容は次のとおりです。
クラスローダーは、Java言語の基本的モジュールです。クラスローダーは、Java仮想マシン(JVM)の構成要素で、クラスをメモリーにロードし、実行時にクラス・ファイルを検索してロードする役割があります。Javaプログラミングを適切に行うためには、クラスローダーとその機能をよく理解する必要があります。この項では、Javaクラスローダーの概要を説明します。
クラスローダーには、親クラスローダーおよび子クラスローダーからなる階層が含まれます。親クラスローダーと子クラスローダーの関係は、オブジェクトのスーパークラスとサブクラスの関係に似ています。ブート・ストラップ・クラスローダーはJavaクラスローダー階層のルートです。Java仮想マシン(JVM)では、ブート・ストラップ・クラスローダーを作成し、このクラスローダーによって、Java Development Kit (JDK)の内部クラスおよびJVMに組み込まれているjava.*
パッケージがロードされます。(java.lang.String
などがロードされます。)
拡張クラスローダーは、ブート・ストラップ・クラスローダーの子です。拡張クラスローダーは、JDKの拡張ディレクトリにあるすべてのJARファイルをロードします。この機能は、クラスパスにエントリを追加することなくJDKを拡張できるので便利です。ただし、拡張ディレクトリ内にあるものは、すべて完全に独立している必要があり、拡張ディレクトリに含まれているクラスまたはJDKクラスしか参照できません。
システム・クラスパス・クラスローダーは、JDK拡張クラスローダーを拡張します。システム・クラスパス・クラスローダーは、JVMのクラスパスからクラスをロードします。アプリケーション固有のクラスローダー(WebLogic Serverのクラスローダーなど)は、システム・クラスパス・クラスローダーの子です。
注意:
Oracleで「システム・クラスパス・クラスローダー」と呼んでいるクラスローダーは、多くの場合、WebLogic Server以外の文脈上では、「アプリケーション・クラスローダー」と呼ばれています。WebLogic Serverにおけるクラスローダーについて説明する際には、Java EEアプリケーションまたはライブラリ関連のクラスローダー(「アプリケーション・クラスローダー」と呼ぶ)と区別するために「システム」という用語を使用します。
クラスローダーでは、クラスのロード時に委任モデルを使用します。クラスローダーの実装では、まずキャッシュをチェックして、リクエストされたクラスがすでにロードされていないか確認します。クラスを確認することで、ディスクからクラスを繰返しロードする代わりに、キャッシュ・メモリーのコピーが使用されるのでパフォーマンスが向上します。キャッシュにクラスがなければ、現在のクラスローダーが親にクラスを要求します。親クラスローダーがクラスをロードできない場合のみクラスローダーはクラスのロードを試行します。親と子両方のクラスローダーにクラスがあると、親のクラスがロードされます。この委任モデルに従うのは、複数の同じ形式のコピーがロードされることを防ぐためです。同じクラスのコピーが複数あると、ClassCastException
が発生する可能性があります。
クラスローダーは、親クラスローダーにクラスのロードを要求してから、クラスを実際にロードします。Webアプリケーションと関連するWebLogic Serverのクラスローダーは、クラスを親に要求する前にまずローカルをチェックするように構成できます。これにより、Webアプリケーションは独自のサード・パーティ・クラスを使用できるようになります。このサード・パーティ・クラスは、WebLogic Server製品の一部として使用することも可能な場合があります。「prefer-web-inf-classes要素」節では、これについてより詳細に説明しています。
weblogic.xml
Webアプリケーションのデプロイメント記述子には、<prefer-web-inf-classes
要素(<container-descriptor
要素のサブ要素)が含まれています。デフォルトでは、この要素はFalse
に設定されています。この要素をTrue
に設定すると、クラスローダーの委任モデルが無効になり、Webアプリケーションからのクラス定義のほうが、より高度なクラスローダーのクラス定義よりも優先的にロードされるようになります。このため、Webアプリケーションは独自バージョンのサード・パーティ・クラスを使用できるようになります。このクラスは、WebLogic Serverの一部としても使用できる場合があります。「weblogic.xmlデプロイメント記述子の要素」を参照してください。
この機能を使用する場合は、Webアプリケーションのクラス定義から作成されたインスタンスと、サーバーの定義から作成されたインスタンスを混在させないように注意してください。これらのインスタンスが混在していると、ClassCastException
が発生します。
例11-1はprefer-web-inf-classes
要素とその定義およびデフォルト値を示します。
例11-1 prefer-web-inf-classes要素
/** * If true, classes located in the WEB-INF directory of a web-app will be * loaded in preference to classes loaded in the application or system * classloader. * @default false */ boolean isPreferWebInfClasses(); void setPreferWebInfClasses(boolean b);
WebLogic Serverでは、サーバーが稼働中にEJBなどのアプリケーション・モジュールの新しいバージョンをデプロイできます。このプロセスは、ホット・デプロイ、またはホット再デプロイと呼ばれ、クラスのロードと密接な関係があります。
Javaクラスローダーには、クラスをアンデプロイしたり、アンロードしたりする標準メカニズムはありません。また、新しいバージョンのクラスをロードすることもできません。実行中の仮想マシンでクラスを更新するには、変更されるクラスをロードしたクラスローダーを、新しいクラスローダーに置き換える必要があります。クラスローダーが置き換えられると、そのクラスローダー(または、そのクラスローダーの子に当たるクラスローダー)からロードされたすべてのクラスを、再ロードする必要があります。また、これらのクラスのインスタンスはすべて、再インスタンス化する必要があります。
WebLogic Serverでは、各アプリケーションに、システム・クラスローダーの子に当たるクラスローダーからなる階層があります。これらの階層により、アプリケーションまたはアプリケーションの一部が、システムの他の部分に影響を与えることなく個別に再ロード可能です。「WebLogic Serverアプリケーションのクラスローディング」で、このトピックについて説明しています。
ポリシー・クラスローダーは、startWebLogicスクリプトを使用してWebLogicサーバーを起動する際のデフォルトのシステム・クラスローダーです。ポリシー・クラスローダーは、クラス・キャッシングおよび索引付けを通じてクラスローダーのパフォーマンスおよびサーバー起動時間を向上し、あらゆるWebLogicモード(開発または本番)でサポートされています。
ポリシー・クラスローダーはロードされたクラスをキャッシュ・ファイルにキャッシュします。それ以降の起動時に、キャッシュされたクラスはバルクに事前ロードされ、サーバー起動など、システム・クラスローダーから多数のクラスをロードするケースでパフォーマンスを向上します。ポリシー・クラスローダーには即時索引も含まれ、これによりソース・コードを含むパッケージ名とJARファイルをマップします。この索引はクラスの参照時間を改善し、欠落しているクラスまたはリソースを探す時間を削減します。キャッシュされたファイルはDOMAIN_HOME/servers/weblogic_name/cache/classloader
ディレクトリで生成されます。
WebLogic Server 12.1.3では、startWebLogic
スクリプトでCLASS_CACHE
の環境変数を設定すると、開発モードでクラス・キャッシングを有効にできます。既存の12.1.3起動スクリプトでは、CLASS_CACHE
変数を引き続き使用してクラス・キャッシングを有効にします。『Oracle WebLogic Serverアプリケーションの開発 12c (12.1.3)』のクラス・キャッシングの構成に関する項を参照してください。
WebLogic Server 12.2.1では、新しいドメインがデフォルトでクラス・キャッシングにポリシー・クラスローダーを使用します。12.2.1にアップグレードする12.1.3ドメインではすべて自動的にポリシー・クラスローダーも使用します。
次の項では、WebLogic Serverアプリケーション・クラスローダーの概要を説明します。
WebLogic Serverのクラスローディングは、アプリケーションの概念に基づいています。アプリケーションは、通常、アプリケーション・クラスを含むエンタープライズ・アーカイブ(EAR)ファイルにパッケージ化されています。EARファイル内にあるものは、すべて同じアプリケーションの一部と見なされます。次のファイルは、EARの一部になることもでき、またスタンドアロンのアプリケーションとしてロードすることも可能です。
Enterprise JavaBean (EJB) JARファイル
WebアプリケーションWARファイル
リソース・アダプタRARファイル
注意:
詳細については、次の各項を参照してください。
リソース・アダプタとクラスローディングについては、「リソース・アダプタ・クラス」を参照してください。
クラスローディング時の一般的なアプリケーション・ファイルのオーバーライド方法の詳細は、『Oracle WebLogic Serverへのアプリケーションのデプロイ』の汎用ファイル・ロード・オーバーライドに関する項を参照してください。
EJBとWebアプリケーションを別々にデプロイすると、これらは2つのアプリケーションと見なされます。2つのファイルをまとめてEARファイル内にデプロイすれば、1つのアプリケーションとなります。したがって、複数のモジュールが同一アプリケーションの一部と見なされるためには、複数のモジュールをまとめてEARファイルにデプロイします。
すべてのアプリケーションは、独自のクラスローダー階層を受け取ります。この階層の親はシステム・クラスパス・クラスローダーです。したがって、アプリケーションどうしが分離されているため、アプリケーションAからアプリケーションBのクラスローダーおよびクラスを見ることはできません。階層クラスローダーには、兄弟概念またはフレンド概念はありません。アプリケーション・コードは、アプリケーション(またはモジュール)と関連するクラスローダーでロードされたクラス、およびアプリケーション(またはモジュール)クラスローダーの祖先に当たるクラスローダーでロードされたクラスからしか見えません。したがって、WebLogic Serverは同一のJVM内の複数の分離したアプリケーションのホストになります。
WebLogic Serverでは、アプリケーションのデプロイ時にクラスローダーの階層が自動的に作成されます。この階層のルート・クラスローダーは、アプリケーション内のすべてのEJB JARファイルをロードします。また、WebアプリケーションWARファイルごとに子クラスローダーが作成されます。
WebアプリケーションによるEJBの呼出しがよくあるため、WebLogic Serverアプリケーション・クラスローダー・アーキテクチャではJavaServer Page (JSP)ファイルおよびサーブレットからその親クラスローダー内のEJBインタフェースを見ることができるようになっています。また、このアーキテクチャではEJB層を再デプロイすることなくWebアプリケーションを再デプロイできます。実際には、EJB層ではなくJSPファイルおよびサーブレットを変更するほうが一般的です。
次の図は、WebLogic Serverアプリケーションのクラスローディング概念を示しています。
アプリケーションにEJBを使用するサーブレットとJSPが含まれる場合:
サーブレットとJSPをWARファイルにパッケージ化します。
Enterprise JavaBeansをEJB JARファイルにパッケージ化します。
このWARファイルとJARファイルをEARファイルにパッケージ化します。
パッケージ化したEARファイルをデプロイします。
WARファイルとJARファイルは別々にデプロイできますが、まとめて1つのEARファイルにしてデプロイすることにより、サーブレットとJSPからEJBクラスを検索できるようにクラスローダーが配置されます。WARファイルとJARファイルを別々にデプロイすると、WebLogic Serverではそれらのファイルごとに兄弟クラスローダーを作成します。したがって、そのWARファイルにはEJBホームおよびリモート・インタフェースを含める必要があり、WebLogic Serverでは、EJBクライアントと実装クラスが異なるJVMにある場合と同様に、EJB呼出しにRMIのスタブ・クラスとスケルトン・クラスを使用する必要があります。この概念については、次の「アプリケーション・クラスローディングと、値渡しまたは参照渡し」の項で詳しく説明しています。
注意:
Webアプリケーション・クラスローダーには、JSPクラスを除く、Webアプリケーションのすべてのクラスが含まれます。JSPクラスは、独自のクラスローダーを取得します。これは、Webアプリケーション・クラスローダーの子に当たります。これにより、JSPを個別に再ロードできます。
アプリケーション用のカスタム・クラスローダーの階層を作成して、クラスの可視性や再ロードを制御しやすくすることができます。この機能を実現するには、weblogic-application.xml
デプロイメント記述子ファイルでclassloader-structure
要素を定義します。
次の図は、WebLogicアプリケーションにおいてクラスローダーがデフォルトではどのように構成されているかを示します。アプリケーション・レベルのクラスローダーは、すべてのEJBクラスがロードされている場所にあります。各Webモジュールについて、そのモジュールのクラス用の子クラスローダーが個別に存在します。
簡素化のため、次の図ではJSPクラスローダーを示していません。
この階層は、EJB呼出し時にcall-by-referenceセマンティクスを使用できるようになるため、大半のアプリケーションにとって最適です。また、これにより他のモジュールに影響を与えることなくWebモジュールを個別に再ロードできるようになります。さらに、Webモジュールの1つで実行されているコードが、任意のEJBモジュールからのクラスをロードできるようになります。これは、使用しているEJBのインタフェースがWebモジュールに含まれることを防げるため便利です。これらの利点のいくつかは、厳密にはJava EEに準拠していないことに注意してください。
カスタム・モジュール・クラスローダーを作成できると、以下のことが可能になる代替的なクラスローダー構成を宣言するメカニズムが得られます。
個々のEJBモジュールを単独で再ロード
モジュールのグループを、一緒に再ロード
特定のWebモジュールとEJBモジュールの親子関係を逆転
EJBモジュール間でネームスペースを分離
Weblogic固有のアプリケーション・デプロイメント記述子weblogic-application.xml
内でクラスローダーの階層を宣言できます。
<!ELEMENT classloader-structure (module-ref*, classloader-structure*)> <!ELEMENT module-ref (module-uri)> <!ELEMENT module-uri (#PCDATA)>
weblogic-application.xml
の最上位要素には、オプションclassloader-structure
要素が含まれます。この要素を指定しない場合は、標準のクラスローダーが使用されます。また、定義の中に特定のモジュールを含めなかった場合、標準的な階層と同様にクラスローダーが割り当てられます。つまり、EJBモジュールはアプリケーションのルート・クラスローダーと関連付けられ、Webアプリケーション・モジュールは独自のクラスローダーを持ちます。
classloader-structure
要素により、classloader-structure
スタンザのネスティングが可能になって、クラスローダーの任意階層を記述できるようになります。現在は、3レベルに制限されています。最も外側のエントリは、アプリケーション・クラスローダーを示します。リストされていないモジュールについては、標準的な階層であると仮定されます。
注意:
JSPクラスローダーは、この定義スキームには含まれません。JSPは常に、所属するWebモジュールと関連のクラスローダーの子クラスローダーにロードされます。
DTD要素の詳細は、エンタープライズ・アプリケーションのデプロイメント記述子の要素を参照してください。
weblogic-application.xml
のclassloader-structure
要素で定義)。<classloader-structure> <module-ref> <module-uri>ejb1.jar</module-uri> </module-ref> <module-ref> <module-uri>web3.war</module-uri> </module-ref> <classloader-structure> <module-ref> <module-uri>web1.war</module-uri> </module-ref> </classloader-structure> <classloader-structure> <module-ref> <module-uri>ejb3.jar</module-uri> </module-ref> <module-ref> <module-uri>web2.war</module-uri> </module-ref> <classloader-structure> <module-ref> <module-uri>web4.war</module-uri> </module-ref> </classloader-structure> <classloader-structure> <module-ref> <module-uri>ejb2.jar</module-uri> </module-ref> </classloader-structure> </classloader-structure> </classloader-structure>
ネスティングの構成は、クラスローダーの階層を示します。上記のスタンザにより、次の図に示す階層がもたらされます。
ユーザー定義のクラスローダーの制約により、再ロードできるものが制御しやすくなり、モジュール間でのクラスの可視性が提供されます。この特徴は主に開発者のためのものです。繰返し開発が行われる場合には有用ですが、本番環境で使用する目的の場合には再ロード機能の使用はお薦めしません。更新時に無効な要素が含まれると、実行中のアプリケーションが破損するおそれがあるためです。ネームスペースの分離とクラス可視性のためのカスタム・クラスローダーの配置は、本番環境で使用する場合においても容認できるものです。ただし、Java EE仕様にはアプリケーションがいかなるクラスローダー構成にも依存してはならないと書いてあることに、プログラマは注意する必要があります。
一部のクラスローダー階層は、アプリケーション内のモジュールが2つの別個のアプリケーションのモジュールのように動作する原因となる可能性があります。たとえば、EJBを独自のクラスローダーに配置して個別に再ロードできるようにすると、Oracleが標準的なクラスローダー階層に提供しているcall-by-referenceによる最適化ではなく、call-by-valueセマンティクスを受け取ります。また、カスタム階層を使用すると、参照が古いものになる可能性があります。したがって、EJBモジュールを再ロードする場合は、呼出し側モジュールも再ロードしてください。
ユーザー定義によるモジュール・クラスローダー階層の作成には、いくつかの制約があります。これらについてはこれ次の項で説明します。
標準のWebLogic Serverクラスローダー階層により、EJBインタフェースがアプリケーション内のすべてのモジュールで利用可能になります。したがって、それ自体のモジュールにインタフェースが含まれていなくても、他のモジュールがEJBを呼び出せます。これが可能なのは、EJBは常にルート・クラスローダーにロードされ、その他のモジュールはすべてそのクラスローダーを共有するか、そのクラスローダーの子に相当するクラスローダーを持つことになるためです。
カスタム・クラスローダー機能があれば、呼び出される側のクラスが呼出し側から見えないようにクラスローダー階層を構成することが可能です。この場合、呼出し側モジュールにインタフェース・クラスを含める必要があります。これは、別個のアプリケーションのモジュールに対して呼出しを行っている場合の要件と同じです。
WebLogic Serverに設けられた標準クラスローダー階層により、アプリケーション内のモジュール間での呼出しでcall-by-referenceセマンティクスを使用することが可能となります。これは、呼出し側が常に同じクラスローダーまたは呼び出される側の子クラスローダーを使用しているためです。この機能により、2つのモジュールがクラスローダー・ツリーにおける別々のブランチに存在するように、クラスローダー階層を構成することが可能になります。この場合、call-by-valueセマンティクスが使用されます。
再ロードに必要となるクラスローダーの切替えは、複数モジュールに渡って原子性を保たないことに留意してください。実際、アプリケーションの更新は、一般に原子性を保ちません。この理由により、タイミングによっては、異なった処理中の操作(変更が行われているときに発生している操作)が、異なったバージョンのクラスにアクセスすることになる可能性があります。
WebLogic Serverを使うと、他のモジュールを同時に再ロードして、EJBモジュール全体を再デプロイする必要なしに、個々のEJBモジュールを再ロードできます。この機能は、現在JSPがWebLogic Serverサーブレットのコンテナに再ロードされている方法に類似しています。
EJBクラスはインタフェースを通じて呼び出されるため、個々のEJB実装クラスをそれ自身のクラスローダーにロードすることが可能です。このようにして、これらのクラスはEJBモジュール全体を再デプロイすることなく個別に再ロードできます。次の図は、単一のEJBモジュールのクラスローダー階層の一例です。2つのEJB (Foo
およびBar
)が含まれています。これは、前の項で説明した一般的なアプリケーション階層におけるサブツリーと考えられます。
展開されたアプリケーションのルートを基準とした相対的な場所にあるファイルの部分的な更新を実行するには、次のコマンド・ラインを使用します。
例11-2 部分的ファイル更新の実行
java weblogic.Deployer -adminurl url -user user -password password -name myapp -redeploy myejb/foo.class
-redeploy
コマンドの後で、更新したい展開アプリケーションのルートを基準として相対的にファイルのリストを指定します。これは、(上記のような)特定の要素へのパスであっても、モジュール(または任意の要素およびモジュールのセット)へのパスであってもかまいません。例:
例11-3 更新のための相対ファイル・リストの指定
java weblogic.Deployer -adminurl url -user user -password password -name myapp -redeploy mywar myejb/foo.class anotherejb
更新するファイル群を指定されると、システムは再デプロイの最小要件を計算しようとします。EJB impl
クラスのみを再デプロイすると、そのクラスのみが再デプロイされることになります。EJB全体(上の例ではanotherejb
)を指定するか、またはEJBホーム・インタフェースを変更して更新する場合、EJBモジュール全体の再デプロイが必要です。
クラスローダーの階層によっては、この再デプロイメントで他のモジュールが再デプロイされることになる可能性があります。具体的には、他のモジュールがEJBクラスローダーを共有する場合や、(WebLogic Serverの標準クラスローダー・モジュールのように) EJBクラスローダーの子クラスローダーにロードされる場合は、これらのモジュールも再ロードされます。
最近のプログラミング言語では、パラメータを渡すときのモデルとして、値渡しと参照渡しがよく使用されます。値渡しの場合、パラメータおよび戻り値はメソッドの呼出しごとにコピーされます。参照渡しの場合は、実際のオブジェクトを示すポインタ(または参照)がメソッドに渡されます。参照渡しでは、オブジェクトをコピーしなくてもよく、渡されたパラメータの状態を変更するメソッドも使用できるため、パフォーマンスが向上します。
WebLogic Serverでは、サーバー内のリモート・メソッド・インタフェース(RMI)呼出しのパフォーマンス向上のための最適化機能もあります。値渡しおよびRMIサブシステムのマーシャリングやアンマーシャリング機能を使用するのではなく、参照渡しを使用することによって、サーバーがダイレクトJavaメソッド呼出しを行います。この方式により、パフォーマンスが大幅に改善され、EJB 2.0ローカル・インタフェースにもこの方式が採用されています。
RMI呼出しの最適化および参照呼出しが使用されるのは、呼出し側と呼び出された側が共に同じアプリケーションにある場合に限られます。通常、クラスローダーが関係します。アプリケーションにはそれぞれ独自のクラスローダー階層があるため、どのアプリケーション・クラスも両方のクラスローダーに定義があり、複数のアプリケーション間で割当てを行おうとするとClassCastExceptionエラーを受け取ります。この問題を回避するため、WebLogic Serverでは複数のアプリケーション間での呼出しには、同じJVM内であっても値呼出しを使用しています。
注意:
複数アプリケーション間の呼出しは、同一アプリケーション内の呼出しに比べて遅くなります。したがって、モジュールは1つのEARファイルにまとめてデプロイし、高速のRMI呼出しおよびEJB 2.0ローカル・インタフェースを使用できるようにしてください。
WebLogic Serverでは、システム・クラスパスにあるJARファイルはWebLogic Serverのシステム・クラスローダーによってロードされます。サーバー・インスタンスの内部で実行されるすべてのアプリケーションは、システム・クラスローダーの子であるアプリケーション・クラスローダー内にロードされます。このシステム・クラスローダーの実装では、アプリケーションは、システム・クラスローダー内にすでに存在する異なるバージョンのサードパーティ製JARを使用できません。すべての子クラスローダーは親(システム・クラスローダー)に対して特定のクラスを要求します。親から見えるクラスをロードすることはできません。
たとえば、com.foo.Baz
というクラスが$CLASSPATH
とアプリケーションEARの両方に存在する場合は、$CLASSPATH
にあるクラスがロードされて、EARのクラスはロードされません。weblogic.jar
は$CLASSPATH
にあるため、アプリケーションはWebLogic Serverクラスをオーバーライドすることはできません。
次の項では、フィルタリング・クラスローダーの定義と使用方法について説明します。
FilteringClassLoader
は、デプロイメント記述子を構成することで、特定のパッケージがシステム・クラスローダーによってロードされるのではなく、常にアプリケーションからロードされるように明示的に指定するメカニズムです。これによって、XercesやAntなどの代替バージョンのアプリケーションを使用できるようになります。FilteringClassLoader
を使用することにより、サード・パーティJARをバンドルしてアプリケーションに使用できますが、javax
パッケージまたはweblogic
パッケージ内のクラスのようなAPIクラスに対してフィルタ処理を行うことはお薦めしません。
FilteringClassLoader
はアプリケーション・クラスローダーとシステム・クラスローダーの間に位置します。システム・クラスローダーの子であり、アプリケーション・クラスローダーの親となります。FilteringClassLoader
はloadClass(String
className
)
メソッドをインターセプトして、weblogic-application.xmlファイルに指定されているパッケージのリストと
classNameを比較します。パッケージと
className
が一致する場合、FilteringClassLoader
はClassNotFoundException
をスローします。この例外は、このクラスをアプリケーションからロードするようにアプリケーション・クラスローダーに通知します。
FilteringClassLoader
を構成して、特定のパッケージがアプリケーションからロードされることを指定するには、アプリケーションからロードされるパッケージのリストを記述しているweblogic-application.xml
に、prefer-application-packages
記述子要素を追加します。次の例は、org.apache.log4j.*
パッケージとantlr.*
パッケージがシステム・クラスローダーではなくアプリケーションからロードされることを示します。
<prefer-application-packages> <package-name>org.apache.log4j.*</package-name> <package-name>antlr.*</package-name> </prefer-application-packages>
prefer-application-packages
記述子要素は、weblogic.xml
でも定義できます。詳細は、「prefer-application-packages
」を参照してください。
EARファイル内に含まれているWARファイルに対して特定のパッケージをロードすることを指定するには、WARファイルのweblogic.xml
ファイルでFilteringClassLoader
を構成します。
たとえば、A.ear
にB.war
が含まれるとします。A.ear
はweblogic-application.xml
でFilteringClassLoader
を定義し、B.war
はweblogic.xml
で別のFilteringClassLoader
を定義します。A.ear
をデプロイすると、B.war
はweblogic.xml
のFilteringClassLoader
に定義されているパッケージをロードします。WARレベルのFilteringClassLoader
は、このWARファイルに対するEARレベルのFilteringClassLoader
より優先されます。
フィルタリング・クラスローダーの構成のヘルプは、「クラスローダー分析ツール(CAT)の使用」を参照してください。
リソースのロード順序は、java.lang.ClassLoader
のgetResource()
およびgetResources()
メソッドがリソースを戻す順序です。フィルタが有効になっている場合、この順序はフィルタ処理が無効な場合とは若干異なります。フィルタが有効になっているということは、FilteringClassLoader
に1つまたは複数のパッケージ・パターンがあることを意味しています。フィルタがない場合(デフォルト)、リソースはクラスローダー・ツリーの上から下へという順序で収集されます。たとえば、Web(1)がリソースをリクエストすると、リソースはシステム(3)、アプリケーション(2)、Web(1)の順序でグループ化されます。例11-4を参照してください。
注意:
FilteringClassLoader
の下で、リソースはデフォルトのJava EE委任モデルに従って返されます。FilteringClassLoader
の親に存在するリソースのみが、返される列挙の最後に追加されます。
図11-4 システム・クラスローダーの使用
System (3) | App (2) | Web (1)
具体的にいうと、すべてのクラスローダーに存在するリソース/META-INF/foo.xml
の場合は、以下のURLのリストが返されます。
META-INF/foo.xml - from the System ClassLoader (3) META-INF/foo.xml - from the App ClassLoader (2) META-INF/foo.xml - from the Web ClassLoader (1)
フィルタリングが有効になっている場合は、システム・クラスローダーのリソースよりも前に、FilteringClassLoader
の子(アプリケーション・クラスローダー)から呼出し側のクラスローダーまでのリソースが戻されます。図11-5では、(D)、(B)、および(A)のすべてのクラスローダーに同じリソースが存在する場合、Webクラスローダーがリソースを要求すると、リソースは次のような順序で取得されます。
META-INF/foo.xml - from the App ClassLoader (B) META-INF/foo.xml - from the Web ClassLoader (A) META-INF/foo.xml - from the System ClassLoader (D)
図11-5 フィルタリング・クラスローダー実装の使用
System (D) | FilteringClassLoader (filterList := x.y.*) (C) | App (B) | Web (A)
アプリケーション・クラスローダーが同じリソースをリクエストした場合は、次のような順序になります。
META-INF/foo.xml - from the App ClassLoader (B) META-INF/foo.xml - from the System ClassLoader (D)
getResource()
の場合は、最初の記述子のみが返されて、getResourceAsStream()
は最初のリソースのinputStream
を返します。
アプリケーションでは、エンタープライズBean、サーブレットとJavaServer Pages、ユーティリティ・クラス、およびサード・パーティ製パッケージなど、様々なJavaクラスを使用します。WebLogic Serverでは、個別のクラスローダーにアプリケーションをデプロイして、独立を維持し、動的な再デプロイメントとアンデプロイメントを容易にします。このため、各モジュールが各クラスに個別にアクセスできるようにアプリケーションのクラスをパッケージ化する必要があります。場合によっては、一連のクラスを複数のアプリケーションまたはモジュールに格納する必要があります。この項では、アプリケーションを正常にステージングするために、WebLogic Serverで複数のクラスローダーを使用する方法について説明します。
クラスローディング問題の分析および解決の詳細は、「クラスローダー分析ツール(CAT)の使用」を参照してください。
各リソース・アダプタは、固有のクラスローダーを使用してクラスをロードするようになりました(Webアプリケーションの場合に類似)。その結果、アプリケーション・アーカイブ(EARファイル)でリソース・アダプタと一緒にパッケージ化されているWebアプリケーションやEJBなどのモジュールは、リソース・アダプタのクラスへの可視性を持ちません。そのような可視性が必要な場合は、リソース・アダプタのクラスをAPP-INF/classesに置く必要があります。また、これらのクラスを(JARユーティリティを使用して)アーカイブし、それらをアプリケーション・アーカイブのAPP-INF/libに置くこともできます。
リソース・アダプタ固有のクラスがWebLogic Serverのシステム・クラスパスにないことを確認してください。リソース・アダプタ固有のクラスをWebモジュール(EJB、Webアプリケーションなど)と共に使用する必要がある場合、それらのクラスを該当するモジュールのアーカイブ・ファイル(EJBに使用するJARファイルまたはWebアプリケーションに使用するWARファイルなど)にまとめます。
WebLogic Serverは、EARファイル内で共有ユーティリティ・クラスを格納できる場所を提供します。ユーティリティJARファイルはAPP-INF/lib
ディレクトリに、個々のクラスはAPP-INF/classes
ディレクトリに置きます。(Jarファイルを/classes
ディレクトリに置いたり、クラスを/lib
ディレクトリに置いたりしないでください。)これらのクラスは、アプリケーションのルート・クラスローダーにロードされます。
この機能により、(どちらに置くかは標準のWebLogic Serverクラスローダーの階層によって変わりますが)システム・クラスパス内にユーティリティ・クラスを置く必要や、EJB JARファイル内にクラスを置く必要はなくなります。この機能を使用する場合は、次の節で説明するマニフェストClass-Path
を使う場合とは少し異なることに注意してください。この機能を使うと、クラス定義はアプリケーション全体で共有されます。マニフェストClass-Path
では、参照しているモジュールのクラスパスが単純に拡張されます。つまり、クラスのコピーが別々に各モジュールについて存在するということです。
Java EE仕様では、クラスの補助的なJARファイルを必要とすることをモジュールで指定する手段としてマニフェストClass-Path
エントリが用意されています。このマニフェストClass-Path
エントリを使用するのは、EJB JARファイルまたはWARファイルの一部として追加の補助的なJARファイルがある場合に限られます。その場合、JARファイルまたはWARファイルの作成時に、必要なJARファイルを参照するClass-Path
要素と共にマニフェスト・ファイルを含める必要があります。
utility.jar
ファイルを参照する簡単なマニフェスト・ファイルを以下に示します。
Manifest-Version: 1.0 [CRLF] Class-Path: utility.jar [CRLF]
このマニフェスト・ファイルの先頭行には、常にManifest-Version
属性を指定する必要があり、次に改行(CR | LF |CRLF)、そしてClass-Path
属性が続きます。マニフェスト・フォーマットの詳細は、http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html
を参照してください。
マニフェストClass-Path
エントリは、エントリが定義されている現在のアーカイブを基準として他のアーカイブを参照します。この構造により、複数のWARファイルおよびEJB JARファイルで、共通のライブラリJARを共有できます。たとえば、WARファイルにy.jar
というマニフェスト・エントリが含まれる場合、このエントリは、以下のように、(WARファイル内ではなく)WARファイルの次に指定する必要があります。
/<directory>/x.war /<directory>/y.jars
マニフェスト・ファイル自体は、META-INF/MANIFEST.MF
のアーカイブに配置します。
詳細は、http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
を参照してください。
CATとはWebベースのクラス分析ツールで、クラスローダー構成のフィルタリングを簡素化し、競合状態の検出、アプリケーションのクラスパスやクラス競合のデバッグといったクラスローディング問題の分析をサポートし、問題解決に役立つソリューションを提案します。
CATはスタンドアロンWebアプリケーションです。wls-cat.war
という1つのWARファイルとして配布され、その機能はWebベース・フロントエンドを使用して公開されます。CATは、開発モードでのみ内部オンデマンド・アプリケーションとしてデプロイされます。デプロイメントは初回のアクセス時に実行されます。サーバーが本番モードで稼働中の場合、自動的にデプロイされません。本番モードでデプロイする際には、その使用に制限はありませんが、他のWebアプリケーションと同様に手動でデプロイする必要があります。CAT Webアプリケーションは、WL_HOME
/server/lib/wls-cat.war
に格納されます。WebLogic Serverバージョン10.3.x以降を対象にデプロイできます。
注意:
CATは、Java用のIBM SDKではサポートされていません。これは、CATアプリケーションの一部の機能がHotSpot実装に依存するためです。
CATには、現在実行中のアプリケーションとモジュールをすべて表示する単一のWeb GUIが実装されています。
CATの使用を開始するには:
WebLogic Server管理コンソールで、「デプロイメント」 > 「app_name」 > 「テスト」を選択し、「クラスローダー分析ツール」リンクを選択します。コンソールのログイン資格証明情報を入力します。
または
ブラウザを開いてhttp://wls-host:port/wls-cat/
へ移動し、コンソールのログイン資格証明情報を入力します。
ナビゲーション・ペインでは、分析するアプリケーションやモジュールを選択し、右側のペインには選択したアイテムの簡単な説明が表示されます。右側のペインを使用して、選択したアプリケーションやモジュールに関する次のようなアクションと分析を実行できます。
クラスローディング競合の分析
システムおよびアプリケーションのクラスローダーの表示
レポートの生成
CATは、システム・クラスパス・クラスローダーやWebLogic Serverのメイン・アプリケーションのクラスローダーによってロードされ、フィルタリング、アプリケーション、およびモジュールのクラスローダーとして定義されたクラスを分析します。クラス、パッケージ、またはJARのレベルで分析を実行できます。選択する各アクションの結果は、基本ビューまたは詳細ビューで表示されます。
CATを使用して実行できるタスクの例を紹介します。
アプリケーションおよびモジュールに関する基本情報の表示
クラスローディング競合の分析
提案されたソリューションの確認
フィルタリング・クラスローダーの構成に関する提案の取得
クラスローダー階層および各クラスローダーのクラスパス全体の表示
クラスローダーにおけるクラス(またはリソース)の検索
アプリケーションには、アプリケーションのクラスパス内に直接存在しないクラスへのマニフェスト参照が複数含まれている場合がありますが、これらのクラスはマニフェスト参照によってクラスパスに連鎖されています。アプリケーション開発者は、知らないうちに別のJARから追加のクラスがアプリケーションのクラスパスに取り込まれ、さらに他のJARへのマニフェスト参照が含まれるようになったことに気付かない場合があります。
cat4mf.ear +- ejb.jar +- web-mf-in-root.war +- lib +- applib.jar +- apputil_1.jar +- apputil_1_1.jar +- apputil_1_1_1.jar +- apputil_1_2.jar +- apputil_1_2_1.jar +- ejbutil_1.jar +- ejbutil_1_1.jar +- ejbutil_1_2.jar +- ejbutil_1_2_1.jar +- webutil_1.jar +- webutil_1_1.jar +- webutil_1_1_1.jar +- webutil_2.jar +- webutil_2_1.jar
次に示すように、ejb.jar
にはejbutil_1.jar
へのマニフェスト参照が含まれ、これによってejbutil_1_1.jar
およびejbutil_1_2.jar
への参照、さらにejbutil_1_2_1.jar
への参照が含まれるようになります。
ejb.jar -> ejbutil_1.jar -> ejbutil_1_1.jar -> ejbutil_1_2.jar -> ejbutil_1_2_1.jar
CATを使用したマニフェスト参照の表示
Java EEライブラリ機能により、複数のエンタープライズ・アプリケーション間で、種類が異なる1つまたは複数のJava EEモジュールを簡単に共有できます。Java EEライブラリは、デプロイメントに際してJava EEアプリケーション・コンテナに登録される1つまたは複数のモジュールです。詳細は、共有Java EEライブラリおよびオプション・パッケージの作成を参照してください。
/lib
ディレクトリへのJARの追加WebLogic Serverでは、ドメイン・ディレクトリ内にlib
サブディレクトリがあります。ドメイン内のWebLogic Serverインスタンスで実行しているすべてのJava EEアプリケーションで(別のシステム・レベル・クラスローダー内)JARファイル・クラスが使用可能になるように、このサブディレクトリを使用して1つまたは複数のJARファイルを追加できます。ドメイン/lib
ディレクトリ内のJARは、システム・クラスパスに追加されません。作成されるクラスローダーは、システム・クラスローダーの子です。ドメイン/lib
ディレクトリのJAR内のすべてのクラスがEARファイルなどのJava EEアプリケーションからのみ参照可能です。システム・クラスパスのクラスはドメイン/lib
ディレクトリ内のクラスにアクセスできません。
lib
サブディレクトリは、サーバーにデプロイされているすべてまたは大部分のアプリケーションで必要とされ、ほとんど変更されないJARファイルを格納するためのディレクトリです。たとえば、lib
ディレクトリを使用して、ドメイン内のすべてのJava EEデプロイメントで必要とされるサード・パーティ・ユーティリティ・クラスを格納できます。ドメイン/lib
クラスローダーはすべてのJava EEアプリケーションの親であるため、サード・パーティ・ユーティリティ・クラスが使用可能になります。
lib
ディレクトリは、ドメインにデプロイされている1つまたは2つのアプリケーションでJARを共有したり、定期的に更新する必要があるJARを共有したりする際の一般的な方法としては推奨できません。lib
ディレクトリ内のJARを更新する場合は、アプリケーションが変更を認識できるように、ドメイン内の全サーバーを再起動する必要があります。複数のアプリケーション間でJARファイルまたはJava EEモジュールを共有する必要がある場合は、共有Java EEライブラリおよびオプション・パッケージの作成で説明されているJava EEライブラリ機能を使用します。
lib
ディレクトリでJARを共有するには: