私たちのアプリケーションでは、次の例外が発生します。
javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
- with linked exception:
[Java.lang.ClassNotFoundException: com.Sun.xml.internal.bind.v2.ContextFactory]
これがCollection.parallelStream()
を使用しているがCollection.stream()
を使用していない場合にのみ起こることをすでにわかりました。
JAXBがクラスをロードするためのThread.currentThread().getContextClassLoader()
を使用することを見ました。また、parallelStream()
を使用する場合、コマンドを実行するためのスレッドは異なるクラスローダを使用しています。時々それはorg.Apache.catalina.loader.WebappClassLoader
であり、時にはjdk.internal.loader.ClassLoaders.AppClassLoader
です。
そして、AppClassLoader
がJAXBの依存関係について知らないのは、WebappClassLoader
が行います。
Java 11と次のMavenの依存関係を使用しています。
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
何が間違っている可能性がありますか?どうやってAppClassLoader
は私たちの依存関係について知らないことになりますか?
私たちは異なる経験をしました。この問題は、Tomcatが各戦争よりも異なるクラスローダーを持っているということでした(私たちは春の起動アプリと似ている何かを見ています。void-mainがアプリケーションランナーのどちらにも異なり)。 「クラスローダーはあなたのアプリケーション内のjarsにアクセスすることはありません - そしてしたがってJAXBはありません。そのため、スレッドを起動したことがある場合(StreamXX.Parallel()またはForkjoinPool.commonthreadpool())、それらのスレッドはbootstrap ClassLoader、アプリケーションのクラスローダーではなく)からなります。バックグラウンドタスクがJAXBをロードするときには、getClass()が実行されます。getContextClassLoader()getResourceAsStream( "xxxx")とリソースが見つかりませんでした。私たちの解決策は明示的なスレッドプールですべてのバックグラウンドタスクを起動し、明示的なスレッドプールファクトリ..スレッドプールファクトリは、呼び出しスレッド(WARまたはSpring-Boot Contextによって初期化されたもの)からクラスローダーをキャプチャします。このクラスローダーはJAXBと友達を持ちます。このスレッドプールファクトリには、明示的なTHR.SetContextClassLoader(GlobalCL)があります。...問題解決(ハックを介して)
このクラスcom.Sun.xml.internal.bind.v2.ContextFactory
は、ファイルrt.jar
までJava 8
に以前に利用でき、jdk
からトリミングされました。
考えられる原因:あなたのアプリケーションはいくつかの古いライブラリを使用します。これはいくつかの古いライブラリを使用します。これはJava 8
を含むxml.bind
を含むjdk 11
からトリミングされます。
回避策:/usr/lib/jvm/jre-1.8.0-openjdk/lib/rt.jar
からファイルjdk 8
を単にコピーすることは、その内容を少しトリミングして、com.Sun.xml.internal.bind.*
パッケージのみを保存することができます。その後、このjar
をTomcat/lib
フォルダに入れます。