parallelStream() causing ClassNotFoundException with JAXB-AP



在我们的应用程序中,我们有时会得到以下异常:

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与应用程序运行器不同)。

无论哪种方式,问题都是"引导"类加载器无法访问应用程序中的jar - 因此没有jaxb。因此,如果您曾经启动过一个线程(例如来自StreamXX.parallel()ForkJoinPool.commonThreadPool()的线程ForkJoinPoolThread),那么这些线程将来自引导类加载器,而不是应用程序的类加载器。因此,如果后台任务第一次加载 JAXB,它们将运行getClass().getContextClassLoader().getResourceAsStream("xxxx")并且找不到资源。

我们的解决方案是在显式线程池中启动所有后台任务,并具有显式线程池工厂。线程池工厂从调用线程(由 war 或 spring-boot 上下文初始化的线程)捕获类加载器。这个类加载器将有jaxb和朋友。所以现在从这个线程池工厂启动的每个线程都有一个显式thr.setContextClassLoader(globalCL);....

问题已解决(通过黑客攻击)

我遇到了类似的问题,我得到了 ClassNotFoundException fororg.apache.xerces.parsers.SAXParser.我已经删除/排除了xercesImplxml-apixmlbeansxmlschema-core的依赖项,问题已经解决,尽管我不知道它为什么以及如何工作。促使我删除这些罐子的是XMLReaderFactory,它存在于JDK 8xml-api中。

您正在从某处加载旧版本的 JAXB。在 Java 11 中,上下文工厂应该是:com.sun.xml.bind.v2.ContextFactory

而不是

com.sun.xml.internal.bind.v2.ContextFactory

https://github.com/eclipse-ee4j/jaxb-api/issues/78

尝试执行以下操作: 将激活包升级到 1.2 。不确定它与它有什么关系,但由于您使用的是java 11,我建议使用激活1.2

而不是插入 jaxB 的玻璃鱼实现。使用以下依赖项:

<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>

或交替

<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>

如果这仍然不起作用,请回退到我写给您的第一件事:

正确的上下文工厂是:

com.sun.xml.bind.v2.ContextFactory

那里某处装着一个旧船。

JDK9 中引入了行为更改: JDK-8184335:发布说明:分叉/联接公共池线程返回系统类装入器作为其线程上下文类装入器(由于 JDK-8172726:ForkJoin 公共池保留对线程上下文类装入器的引用)。

另请参阅 jdk8 和 jdk11 中的不同类加载器。

>这个类com.sun.xml.internal.bind.v2.ContextFactory以前在文件中可用,rt.jar直到java 8,然后从jdk中被修剪掉。


可能的原因:您的应用程序使用一些库,该库使用一些旧库,该库需要java 8,其中包含xml.bind,这是从jdk 11中修剪掉的。

>解决方法:您只需从jdk 8复制文件/usr/lib/jvm/jre-1.8.0-openjdk/lib/rt.jar,稍微修剪一下其内容,仅保存com.sun.xml.internal.bind.*包。然后将此jar放入您的tomcat/lib文件夹中。

相关内容

  • 没有找到相关文章

最新更新