・・・(5分後)Aさん:「問題が発生しました。・・・WebSphere自体が立ち上がらなくなってしまいました。LAST」の存在意義は、まさにこの冗談のような無茶がもたらす悲劇を2度と繰り返さないためです。LAST」に変更することでした。WebSphereそのものに影響を全く与えることなく、自分のWebアプリケーション内に含まれるライブラリーが先に優先されるようになります。これこそが、クラスローダー・ツリーがもたらすメリットです。LAST」にする必要性だって?いつでもさ。Serverが内部でどんなライブラリーを使用していようとも、それに影響されることなく自分の好きなライブラリーの最新バージョンを使用したいという欲求は開発者なら誰もが思うところです。LAST」にするのは自然なことです。実際、サーブレット仕様でもこのことについて触れている箇所があります。SRV.9.7.2からの引用です。JARs.アプリケーションのクラスをロードするクラスローダーは、アプリケーション・サーバー、Webコンテナ全体で使用するライブラリー内よりも、WAR内部のクラスやリソースを優先してロードすることが推奨される。"recommended(推奨)"ですから、必須事項ではありません。FIRST」であることは、仕様に違反しているわけではないです。褒められたものではありませんが・・・。LAST」に設定することです。LAST」にしても、「上書き」できません。これはJavaのセキュリティー・モデルで禁止されています。これを許すと、攻撃者に内部攻撃の機会を与えてしまうことになります。java.lang.String等を勝手に書き換えられたら、java.lang.Stringの不変性に依存しているクラスなどは、その前提が破壊されていまうことになり、重大なセキュリティー・リスクを背負うことになります。ちなみに、他のアプリケーション・サーバー、たとえばWebコンテナーであるTomcatはどうなっているか見てみましょう。HOW-TO」からTomcatのクラスローダー・ツリーについて説明した図を以下に引用します(図4)。(US)図4:Tomcatにおけるクラスローダー・ツリークリックして大きなイメージを見るTomcatの場合は、EARが存在せず、Webアプリケーション(WAR)だけですので、若干の違いはあります。それでも、図4において、Tomcatでは「common」「share」配下よりも各「webapp」内のクラス・リソースが優先されると、ドキュメントには明記されています。LAST」の設定になっているわけです。LAST」設定ですが、これは通常のJavaのクラスローダーのデリゲーション・モードとは異なる設定です。そのため普段はなかなかお目にかかることのできない不思議な現象を作り出すことができます。リスト2をご覧ください。}}一見したところ何の変哲もないおなじみのシングルトン・パターンです。クラスcom.example.Singletonのインスタンスはひとつしか存在しないはずです。?ここで、以下のルールを紹介しましょう。クラスの同一性に関するルール全く同じパッケージ名・同じ名前のクラスでも、違うクラスローダーからロードされたものは、同一クラスとは扱われません。別クラス扱いとなります。このルールを使用すればシングルトンが唯一のものだという固定観念を破ることは簡単に行えます。サンプルとして以下のようなEARを用意してみましょう。com.example.web.ClassLoaderTestServletシングルトン・クラスを、EJBモジュール、Webモジュール、両方に入れておきます。LAST」に設定します。クラスローダーの観点で見た場合は、図5のようになります。図5:クラス配置図クリックして大きなイメージを見るこの状態でシングルトンのテストをしてみましょう。テストコードはリスト4のようになります。}}テストコードを見てみましょう。Webモジュール内のサーブレットClassLoaderTestServletと、EJBモジュール内のクラスInEJBの中では、どちらも同じシングルトン・クラスcom.example.Singletonを使用しています。シングルトン・インスタンスのcounter値を増加して値がどのように変化したか、そのつど表示しています。このサーブレッドを実行してみましょう。シングルトンですので、結果はリスト5のようになると予想されます。11しかし、実際の出力結果はリスト6のようになります。1実行結果からなにが読み取れるでしょうか?そうです。シングルトンはひとつではありません。Webモジュール内のサーブレット、EJBモジュール内のクラスInEJB、それぞれ違うシングルトンのインスタンスを見ているのです。LAST」に設定したため、サーブレットがシングルトン・クラスを探しにいくとき、最初に見つかるのは、WARクラスローダー内のシングルトン・クラスです。クラスInEJBからは同じEJBモジュール内のシングルトン・クラスが最初に見つかります。アプリケーション・クラスローダー、WARクラスローダー、それぞれのクラスローダーが、まったく同じ名前のクラスcom.example.Singletonをそれぞれ別々にロードすることになります。シングルトン・クラスのstatic変数instanceも、それぞれのクラスに存在します。そのため、今回のように、シングルトンのインスタンスが2つ存在する結果となったのです。FIRST」なら、このようなことは起きませんでした(図7)。Webアプリケーション内にシングルトン・クラスを入れておいても、サーブレットからはアプリケーション・クラスローダー配下のシングルトン・クラスが先に見つかります。アプリケーション・クラスローダーがロードしたシングルトン・クラスが、両方で使用されることになります。そのため、シングルトンはまさに「JVM全体でシングルトン」の役割を果たすことになります。FIRST」の場合クリックして大きなイメージを見るひとつのJVM内で、クラスを識別するキーとなるのは「パッケージ名+クラス名」ではないのです。「パッケージ名+クラス名+ロードしたクラスローダー」が識別のためのキーとなるのです。LAST」の必要性、クラスの同一性に関する話題を扱いました。次回の「ドッペルゲンガーの恐怖」では、いよいよJ2EEの世界で、EARをどのようにパッケージングすればよいか、具体的なパッケージング戦略について解説していきます。ライブラリーはどこにおけばよいか、モジュール分割の方針、さらに世にも恐ろしいドッペルゲンガー現象について説明します。LASTにして、WEB-INF/libにライブラリーは何でも気にせず全部放り込んでおけば大丈夫」という考え方がいかに危険であるか、解説していきたいと思います。Proxyを使用して実現するという「トリッキー」なテクニックがあります。第1回、第2回と解説したクラスローダーに関する基礎知識は、このような不可能を可能にする応用例にも生かすことにもできます。これらのテクニックは、数少ないJavaの醍醐味のうちのひとつです。アプリケーション・サーバー以外の世界でも、Java開発者にとってクラスローダーに関する知識は、Javaを続けていく限り将来役にたつときが必ずやってくることでしょう。WebSphereの日本の技術情報サイトですコメントコメントを登録するにはサインインあるいは登録してください。