Payara(Glassfish)のライブラリフォルダとクラスローダの関係

f:id:Naotsugu:20210424133326p:plain


要約

外部ライブラリ格納フォルダとクラスローダの関係は以下のようになります。

  • Bootstrap class loader
    • Extension class loader domain-dir/lib/ext
      • Public API class loader
        • Common class loader domain-dir/lib
          • LifeCycleModule class loader
          • Connector class loader
            • Applib class loader lib\applibs
              • Archive class loader

domain-dir/lib/ext には、アプリケーションサーバ自体が必要とする拡張ライブラリを配備します。Java EE API に依存したライブラリなどは配備できません。

domain-dir/libには、JDBCドライバやカスタムログインモジュールやレルムなどのアプリケーションサーバで共通的に利用するライブラリを配備します。

lib\applibsには、デプロイ時に指定するアプリケーション用のライブラリを配備します。


各クラスローダの役割

Bootstrap class loader

JVMが提供する基本的なランタイム・クラスをロード。

Extension class loader

システム拡張ディレクトリdomain-dir/lib/ext に存在するJARファイルからクラスをロード。

Public API class loader

GlassFish Serverランタイムによってエクスポートされたすべてのクラスをロード。 Java EE API などが含まれる。

Common class loader

domain-dir/lib/classes 内のクラスファイル(.propertiesなども含む)、domain-dir/lib の JARファイルからクラスをロード(as-install/lib ディレクトリ内のJARファイルのロードも行うが、利用者がここを利用することは推奨されない)。 ロードの順序は as-install/lib domain-dir/lib/classes domain-dir/lib の順番。 JDBCドライバやカスタムログインモジュールとレルムはなどの JAR はここに配備する。

Connector class loader

個別にデプロイされたコネクターモジュールをロード。 すべてのアプリケーションで共有される。

LifeCycleModule class loader

ライフサイクル・モジュール毎に作成され、各ライフサイクル・モジュールのクラスパスを使用た独自のクラスローダとなる。

Applib class loader

展開時に指定された特定の有効モジュールまたは Java EE アプリケーション用のライブラリクラスをロード。 このクラスローダのインスタンスは、アプリケーション毎に1つ、個別にデプロイされた EAR JAR や Web WAR 毎に 1 つ存在する。 デプロイされた複数のアプリケーションが同じライブラリを使用する場合、ライブラリの同じインスタンスを共有する(ライブラリが別のライブラリのクラスを参照することはできない)。

Archive class loader

デプロイされたアプリケーションやモジュールのWAR、EAR、JARファイルやディレクトリ(ディレクトリ・デプロイの場合)からクラスをロード(スタブ・クラスやJSPページで生成されるサーブレットなど、GlassFish Serverランタイムが生成するアプリケーション固有のクラスも含む)。


add-library

asadmin コマンドの add-library で外部ライブラリを登録できます。

asadmin> add-library --type={ext|common|app} library-file-path [library-file-path ... ]

--type でそれぞれの格納先を制御できます。

ext を指定した場合 domain-dir/lib/ext に格納されます。

common を指定した場合 domain-dir/lib に格納されます。

app を指定した場合 lib\applibs に格納されます。


Logback 利用時の注意点

アプリケーションサーバ自身のロガーを変更したい場合、例えば以下のコマンドでロガーのハンドラを変更することができます。

asadmin> set-log-attributes "handlers=org.slf4j.bridge.SLF4JBridgeHandler"

このコマンドにより、domain-dir/config/logging.properties に以下が反映されます。

handlers=org.slf4j.bridge.SLF4JBridgeHandler

必要なライブラリJARは以下となります。 * slf4j-api-x.x.x.jar * jul-to-slf4j-x.x.x.jar * logback-core-x.x.x.jar * logback-classic-x.x.x.jar

これらは以下のコマンドで登録できます(直接フォルダに置いても同じです)。

asadmin> add-library --type=ext slf4j-api-x.x.x.jar jul-to-slf4j-x.x.x.jar logback-core-x.x.x.jar logback-classic-x.x.x.jar

しかしこの場合、logback-classic-x.x.x.jar は services を経由して ServletContainerInitializer に依存してしまっているので ClassNotFoundException になります。

詳細は以下を参照してください。

blog1.mammb.com


logback-classic-x.x.x.jar の中にある META-INF/services/javax.servlet.ServletContainerInitializer を削除すれば、一旦は対処することができます。