java.lang.LinkageError 在 Tomcat9 上:java.net.URLClassLoader 尝试为 DefaultTokenServices 重复 class 定义

java.lang.LinkageError on Tomcat9: java.net.URLClassLoader attempted duplicate class definition for DefaultTokenServices

我公司的后端应用程序 war 大小约为 100 MB,因此我们决定将所有 Maven 依赖项的范围更改为提供。罐子从 .war 移动到 opt/tomcat/shared/lib 文件夹(根据此说明 https://www.mulesoft.com/tcat/tomcat-classpath)。 一切正常,我们使用此配置在此服务器上部署了 2 个后端应用程序。添加第三个类似的后端应用程序后,我们无法使用登录 oauth2 服务,因为在日志中我们可以看到以下错误:

org.springframework.cglib.core.CodeGenerationException: java.lang.LinkageError-->loader java.net.URLClassLoader @2f943d71 (instance of java.net.URLClassLoader, child of java.net.URLClassLoader @bd8db5a java.net.URLClassLoader) attempted duplicate class definition for org.springframework.security.oauth2.provider.token.DefaultTokenServices$$FastClassBySpringCGLIB$a1f25c.

前两个应用程序还可以,但第三个不行。在每次部署之前,我们都会清除 tomcat 的工作文件夹。 我们使用Java11 SpringBoot2,OpenJDK 11,Tomcat9.0.21。 Class DefaultTokenServices 在 spring-security-oauth2-2.3.5.RELEASE.jar 中,我们将其与其他 jars 放在 opt/tomcat/shared/lib 文件夹中。

可能是因为同一个jar文件有两个版本。

我认为 Tomcat 的 SharedClassLoader(用于从 Tomcat 的 tomcat/shared/lib 文件夹加载 jar)不是' t 线程安全,因为当 2 个或更多线程尝试并行定义相同的 class 时,似乎会发生此 LinkageError。

解决方法是给JVM添加AllowParallelDefineClass标志(tomcat/bin/catalina.sh)。这导致当 2 个或更多线程尝试并行定义相同的 class 时,它们都将返回第一个请求者的结果,而不是抛出错误。

-XX:+AllowParallelDefineClass