Javaクラスローダーは通常、固定された順序で1つ以上の場所でクラスを探すことによって機能します。たとえば、コマンドラインからアプリケーションを実行するときにアプリケーションをロードするクラスローダーは、最初にrt.jar
ファイル(およびブートクラスパス上の他のファイル)を検索し、次にクラスパスで指定されたディレクトリとJARファイルを検索します。
Webアプリのクラスローディングは原則的には似ていますが、実際にはもう少し複雑です。特定のWebアプリの場合、Webアプリケーションのクラスローダーは次の順序でクラスを検索します。たとえば、Tomcat6は次の順序でクラスを検索します。
- JVMのブートストラップクラス
- システムクラスローダークラス(ここで説明)
- / WEB-INF/webappのクラス
- Webアプリの/WEB-INF/lib/*.jar
- $ CATALINA_HOME / lib
- $ CATALINA_HOME / lib/*。jar
もちろん、クラスローダーが探しているクラスを見つけると、それ以上は検索されません。そのため、順序の後半にある同じ名前のクラスはロードされません。
複雑なのは、WebコンテナにはWebアプリケーションごとに1つのクラスローダーがあり、これらのクラスローダーは共通のクラスを管理する他のクラスローダーに委任することです。実際には、これは、一部のクラスがコンテナ全体に対して1回だけロードされることを意味し(たとえば、1と2)、他のクラスは異なるクラスローダーによって複数回ロードされる可能性があります。
(クラスが複数回ロードされると、個別のClass
オブジェクトと個別のクラススタティックが生成されます。JVMに関する限り、クラスのバージョンは異なるタイプであり、あるバージョンから別のバージョンに型キャストすることはできません。)
最後に、Tomcatは、個々のWebアプリケーションを「ホットロード」できるように構成できます。これには、Webアプリケーションを停止し、そのWebアプリ用の新しいクラスローダーを作成して、再起動する必要があります。
ファローアップ
それで...静的メソッドを同期しても、クラスが複数回ロードされている共有リソースへのアクセスは保護されませんか?
詳細にもよりますが、おそらくそうではありません。(または、別の方法で、クラスが実際に複数回ロードされているかどうかを確認するには、クラスstatic
の各「ロード」のメソッドが異なるstatic
フィールドのセットにアクセスします。)
シングルトンアプリケーションクラスインスタンスを同じコンテナ内の複数のWebアプリケーションで共有したい場合は、クラスを$CATALINA_HOME/lib
または同等のものに配置するのが最も簡単です。ただし、これが優れたシステム設計であるかどうかも自問する必要があります。Webアプリを組み合わせるか、共有データ構造の代わりにリクエスト転送などを使用することを検討してください。シングルトンパターンはwebappsで厄介になる傾向があり、このフレーバーはさらに厄介です。