クラスローダーのハウツー

目次

概要

多くのサーバーアプリケーションと同様に、Tomcatは様々なクラスローダー(すなわち、java.lang.ClassLoaderを実装するクラス)をインストールし、コンテナの異なる部分やコンテナ上で実行されるWebアプリケーションが、利用可能なクラスやリソースの異なるリポジトリにアクセスできるようにします。このメカニズムは、Servlet Specificationバージョン2.4で定義されている機能、特にセクション9.4および9.6を提供するために使用されます。

Java環境では、クラスローダーは親子ツリー構造で配置されます。通常、クラスローダーが特定のクラスまたはリソースのロードを要求されると、まず親クラスローダーにその要求を委譲し、親クラスローダーが要求されたクラスまたはリソースを見つけられない場合にのみ、自身のリポジトリを検索します。ただし、後述するように、Webアプリケーションのクラスローダーのモデルはこれとわずかに異なりますが、主要な原則は同じです。

Tomcatが起動されると、次の親子関係に整理された一連のクラスローダーが作成されます。ここでは、親クラスローダーが子クラスローダーの上に位置します

      Bootstrap
          |
       System
          |
       Common
       /     \
  Webapp1   Webapp2 ...

これらの各クラスローダーの特性、およびそれらが可視化するクラスとリソースのソースについては、次のセクションで詳しく説明します。

クラスローダーの定義

上記の図に示されているように、Tomcatは初期化時に次のクラスローダーを作成します

  • Bootstrap — このクラスローダーには、Java仮想マシンによって提供される基本的なランタイムクラスと、System Extensionsディレクトリ (`$JAVA_HOME/jre/lib/ext`) に存在するJARファイルからのクラスが含まれます。注意: 一部のJVMでは、これを複数のクラスローダーとして実装する場合や、(クラスローダーとして)まったく可視化されない場合があります。

  • System — このクラスローダーは通常、CLASSPATH環境変数の内容から初期化されます。そのようなクラスはすべて、Tomcat内部クラスとWebアプリケーションの両方から可視です。ただし、標準のTomcat起動スクリプト (`$CATALINA_HOME/bin/catalina.sh` または `%CATALINA_HOME%\bin\catalina.bat`) は、CLASSPATH環境変数自体の内容を完全に無視し、代わりに以下のリポジトリからシステムクラスローダーを構築します

    • _`$CATALINA_HOME/bin/bootstrap.jar`_ — Tomcatサーバーを初期化するために使用されるmain()メソッドと、それに依存するクラスローダー実装クラスが含まれています。

    • _`$CATALINA_BASE/bin/tomcat-juli.jar`_ または _`$CATALINA_HOME/bin/tomcat-juli.jar`_ — ロギング実装クラス。これには、Tomcat JULIとして知られるjava.util.logging APIの拡張クラスと、Tomcatが内部的に使用するApache Commons Loggingライブラリのパッケージ名を変更したコピーが含まれます。詳細については、ロギングドキュメントを参照してください。

      tomcat-juli.jarが_`$CATALINA_BASE/bin`_に存在する場合、_`$CATALINA_HOME/bin`_にあるものの代わりに使用されます。これは特定のロギング設定で役立ちます

    • _`$CATALINA_HOME/bin/commons-daemon.jar`_ — Apache Commons Daemonプロジェクトのクラス。このJARファイルはcatalina.bat|.shスクリプトによって構築されるCLASSPATHには存在しませんが、_`bootstrap.jar`_のマニフェストファイルから参照されます。

  • Common — このクラスローダーには、Tomcat内部クラスとすべてのWebアプリケーションの両方から可視となる追加のクラスが含まれています。

    通常、アプリケーションクラスはここに配置すべきではありません。このクラスローダーが検索する場所は、$CATALINA_BASE/conf/catalina.properties の common.loader プロパティで定義されています。デフォルト設定では、以下の場所がリストされた順序で検索されます

    • _`$CATALINA_BASE/lib`_内の展開されたクラスとリソース
    • _`$CATALINA_BASE/lib`_内のJARファイル
    • _`$CATALINA_HOME/lib`_内の展開されたクラスとリソース
    • _`$CATALINA_HOME/lib`_内のJARファイル

    デフォルトでは、以下が含まれます

    • _annotations-api.jar_ — Jakarta Annotations 3.0 クラス。
    • _catalina.jar_ — TomcatのCatalinaサーブレットコンテナ部分の実装。
    • _catalina-ant.jar_ — オプション。マネージャーWebアプリケーションで動作するためのTomcat Catalina Antタスク。
    • _catalina-ha.jar_ — オプション。Tribes上に構築されたセッションクラスタリング機能を提供する高可用性パッケージ。
    • _catalina-ssi.jar_ — オプション。サーバーサイドインクルードモジュール。
    • _catalina-storeconfig.jar_ — オプション。現在の状態からのXML設定ファイルの生成。
    • _catalina-tribes.jar_ — オプション。高可用性パッケージで使用されるグループ通信パッケージ。
    • _ecj-*.jar_ — オプション。JSPをサーブレットにコンパイルするために使用されるEclipse JDT Javaコンパイラ。
    • _el-api.jar_ — オプション。EL 6.0 API。
    • _jakartaee-migration-*-shaded.jar_ — オプション。Java EE 8からJakarta EE 9へのWebアプリケーションの変換を提供します。
    • _jasper.jar_ — オプション。Tomcat Jasper JSPコンパイラとランタイム。
    • _jasper-el.jar_ — オプション。Tomcat EL実装。
    • _jaspic-api.jar_ — Jakarta Authentication 3.1 API。
    • _jsp-api.jar_ — オプション。Jakarta Pages 4.0 API。
    • _servlet-api.jar_ — Jakarta Servlet 6.1 API。
    • _tomcat-api.jar_ — Tomcatによって定義されたいくつかのインターフェース。
    • _tomcat-coyote.jar_ — Tomcatコネクタとユーティリティクラス。
    • _tomcat-dbcp.jar_ — オプション。Apache Commons Pool 2およびApache Commons DBCP 2のパッケージ名を変更したコピーに基づくデータベース接続プール実装。
    • _tomcat-i18n-**.jar_ — オプションのJARで、他の言語のリソースバンドルが含まれています。デフォルトのバンドルも各個別のJARに含まれているため、メッセージの国際化が不要な場合は安全に削除できます。
    • _tomcat-jdbc.jar_ — オプション。Tomcat JDBCプールとして知られる、別のデータベース接続プール実装。詳細についてはドキュメントを参照してください。
    • _tomcat-jni.jar_ — Tomcat Nativeライブラリとの統合を提供します。
    • _tomcat-util.jar_ — Apache Tomcatの様々なコンポーネントで使用される共通クラス。
    • _tomcat-util-scan.jar_ — Tomcatで使用されるクラススキャン機能を提供します。
    • _tomcat-websocket.jar_ — オプション。Jakarta WebSocket 2.2 実装
    • _websocket-api.jar_ — オプション。Jakarta WebSocket 2.2 API
    • _websocket-client-api.jar_ — オプション。Jakarta WebSocket 2.2 クライアントAPI
  • WebappX — 単一のTomcatインスタンスにデプロイされる各Webアプリケーションに対してクラスローダーが作成されます。Webアプリケーションの/WEB-INF/classesディレクトリ内のすべての展開されたクラスとリソース、およびWebアプリケーションの/WEB-INF/libディレクトリ下のJARファイル内のクラスとリソースは、このWebアプリケーションからのみ可視であり、他のWebアプリケーションからは可視ではありません。

前述のように、Webアプリケーションのクラスローダーは、デフォルトのJava委譲モデルとは異なります(Servlet Specificationバージョン2.4、セクション9.7.2 Web Application Classloaderの推奨事項に従っています)。Webアプリケーションの_WebappX_クラスローダーからクラスをロードする要求が処理される際、このクラスローダーは、検索前に委譲するのではなく、ローカルリポジトリを最初に検索します。例外もあります。JREの基本クラスの一部であるクラスはオーバーライドできません。XMLパーサーコンポーネントのように、アップグレード可能なモジュール機能を使用してオーバーライドできるいくつかの例外があります。最後に、Tomcatが実装する仕様(Servlet、JSP、EL、WebSocket)のJakarta EE APIクラスについては、Webアプリケーションのクラスローダーは常に最初に委譲します。Tomcatの他のすべてのクラスローダーは、通常の委譲パターンに従います。

したがって、Webアプリケーションの観点からは、クラスまたはリソースのロードは以下のリポジトリをこの順序で検索します

  • JVMのBootstrapクラス
  • Webアプリケーションの_`/WEB-INF/classes`_
  • Webアプリケーションの_`/WEB-INF/lib/*.jar`_
  • システムクラスローダーのクラス(上記参照)
  • 共通クラスローダーのクラス(上記参照)

Webアプリケーションクラスローダーが<Loader delegate="true"/>で設定されている場合、順序は次のようになります

  • JVMのBootstrapクラス
  • システムクラスローダーのクラス(上記参照)
  • 共通クラスローダーのクラス(上記参照)
  • Webアプリケーションの_`/WEB-INF/classes`_
  • Webアプリケーションの_`/WEB-INF/lib/*.jar`_

XMLパーサーとJava

Tomcatの古いバージョンでは、Tomcatライブラリディレクトリ内のXMLパーサーを置き換えるだけで、すべてのWebアプリケーションで使用されるパーサーを変更できました。しかし、現在のバージョンのJavaを実行している場合、この手法は効果がありません。なぜなら、通常のクラスローダー委譲プロセスが、常にJDK内の実装を優先して選択するためです。

Javaは、JCPの外部で作成されたAPI(W3CのDOMやSAXなど)の置き換えを可能にする、アップグレード可能なモジュールと呼ばれるメカニズムをサポートしています。これはXMLパーサーの実装を更新するためにも使用できます。

JREコンポーネントをオーバーライドすることにはリスクが伴います。オーバーライドするコンポーネントが100%互換性のあるAPIを提供しない場合(例:Xercesが提供するAPIがJREが提供するXML APIと100%互換性がない場合)、Tomcatやデプロイされたアプリケーションでエラーが発生する可能性があります。

高度な設定

より複雑なクラスローダー階層も設定可能です。以下の図を参照してください。デフォルトでは、ServerおよびSharedクラスローダーは定義されておらず、上記の簡易的な階層が使用されます。このより複雑な階層は、conf/catalina.propertiesserver.loaderおよび/またはshared.loaderプロパティの値を定義することで使用できます。


  Bootstrap
      |
    System
      |
    Common
     /  \
Server  Shared
         /  \
   Webapp1  Webapp2 ...

Server クラスローダーはTomcat内部のみに可視であり、Webアプリケーションからは完全に不可視です。

Shared クラスローダーはすべてのWebアプリケーションに可視であり、すべてのWebアプリケーション間でコードを共有するために使用できます。ただし、この共有コードを更新するにはTomcatの再起動が必要です。