REGEXを使ったWebLogicの優先パッケージ指定

著者
Damian
Terlecki
1分間の読書
JEE
<wls:container-descriptor><wls:prefer-application-packages><wls:package-name>org.eclipse.persistence(?!\.jaxb)</wls:package-name></wls:prefer-application-packages></wls:container-descriptor>

Java EEサーバーであるWebLogicは、コンテナが標準で提供するライブラリを上書きする機能を提供しています。 このような設定は、WARアーティファクトのWEB-INFフォルダに配置されたweblogic.xmlディスクリプタ、またはEARアーカイブのMETA-INFディレクトリに置かれたweblogic-application.xmlディスクリプタを通じて可能です。

prefer-application-packagesprefer-application-resources要素の例は、それぞれクラスとリソースをロードするために簡単に見つけることができます。 サンプルのフィルタは、時に.*サフィックスで終わることもあり、終わらないこともあり、REGEXやGLOBに似ています。 しかし、ドキュメントではこのフォーマットの詳細が説明されておらず、複雑なフィルタリングを適用したい場合には、その詳細が非常に重要になります。

<wls:container-descriptor>
    <wls:prefer-application-packages>
        <wls:package-name>com.sample.*</wls:package-name>
    </wls:prefer-application-packages>
</wls:container-descriptor>

上記の設定は、com.samplecom.sample.examplecom.sample.example.subexampleのパッケージ、またはいずれかの組み合わせのクラスを優先するのでしょうか? com.sample.exampleを除くcom.sample.*のすべてのパッケージにマッチングするように設定するにはどうすればよいでしょうか? クラスを完全名までフィルタリングできるのか、それともこの機能はパッケージにのみ適用されるのでしょうか(要素の名前から推測)?

WebLogicのFilteringClassLoader

すべての疑問はコードに行き着きます。FilteringClassLoaderは、WebLogicが提供する依存関係の中から探すべきクラスです。 この名前は、もう一つの便利なツールであるClassloader Analysis Toolのレポートから来ています。 このクラスは、T3プロトコルクライアントライブラリ${WL_HOME}/server/lib/wlthint3client.jarをロードするとすぐに見つかります。 より正確には、weblogic.utils.classloadersパッケージに存在します。

ライセンス上の理由により、このライブラリはMaven Centralリポジトリから解決できません。 検証目的で、WLSのインストールの代替として、公式dockerイメージのコンテナから抽出することができます。

#!/bin/bash
# Login, review and accept license at https://container-registry.oracle.com/ > Middleware > weblogic 
docker login container-registry.oracle.com
image=container-registry.oracle.com/middleware/weblogic:14.1.1.0-dev
sourcePath=/u01/oracle/wlserver/server/lib/wlthint3client.jar
destinationPath=./
containerId=$(docker create "$image")
docker cp "$containerId:$sourcePath" "$destinationPath"
docker rm "$containerId"

さて、weblogic.utils.classloaders.FilteringClassLoaderのバイトコードは、以下のアルゴリズムに翻訳されるようです。

  1. パターンをロードし、末尾の*文字を削除します。
  2. パターンが.で終わる場合、{0,1}サフィックスを追加します。
  3. パターンに^プレフィックスを追加します。
  4. java.util.regex.Patternを作成し、find()メソッドを使用してクラス/リソースの完全名に対してmatcher(String)を呼び出します。
  5. マッチが見つからない場合、loadClass/getResourceInternal/getResource/getResourcesのロードを親クラスローダーに委譲し、それ以外の場合はアプリケーションによって提供されたクラス/リソースを返します。

これは、prefer-application-packagesprefer-application-resources要素が、REGEXを使用してパッケージとリソース、および個々のクラスを細かくフィルタリングできることを示しています。 開始文字と終了文字*および.に関して、いくつか追加があることに注意してください。

行末文字はパターンに追加されません。find()メソッドの使用と組み合わせることで、部分的な(matches()の代替としての)マッチングにより、フィルタリングされるパケットの数が増加します。 さらに、パッケージセパレータはここでは任意の文字マッチとして機能し、一見すると曖昧であり、非常にまれに意図したよりも広いフィルタリングにつながる可能性があります。

最後に、このメカニズムでは、サブパッケージをスキップする正規表現を定義できます。このような表現(例:^com.sample(?!\.example$))は、他のマッチが見つからない場合、WLSが提供するライブラリセットへのフォールバックを引き起こします。 ただし、単純な表現を使用するようにしてください。過度のバックトラッキングは、アプリケーションの初期化時間の増加につながる可能性があります。