Jenkins升级后Maven任务遇java.lang.LinkageError求解决方案
问题描述
Jenkins从2.235.1版本升级至2.375.1版本后,使用Swarm Client 3.39的Jenkins Agent运行Maven任务时失败,抛出java.lang.LinkageError错误,提示org.slf4j.Logger接口被不同类加载器加载。推测是Maven 3与Swarm Client 3.39的slf4j依赖冲突。POM中未直接引入slf4j,仅包含log4j-api和log4j-core依赖,尝试添加provided scope无效,寻求解决方案。
任务失败日志
[EnvInject] - Variables injected successfully. Parsing POMs Established TCP socket on 46713 maven35-agent.jar already up to date maven35-interceptor.jar already up to date maven3-interceptor-commons.jar already up to date [get-automated-testing] $ /etc/alternatives/jre_11_openjdk/bin/java -Xmx8192m -XX:+UseParallelGC -Duser.language=en -Duser.country=GB -verbose:gc -cp /var/lib/jenkins/maven35-agent.jar:/opt/maven/boot/plexus-classworlds-2.5.2.jar:/opt/maven/conf/logging jenkins.maven3.agent.Maven35Main /opt/maven/ /opt/swarm-client-3.39.jar /var/lib/jenkins/maven35-interceptor.jar /var/lib/jenkins/maven3-interceptor-commons.jar 46713 [0.009s][info][gc] Using Parallel <===[JENKINS REMOTING CAPACITY]===>channel started [WARNING] LinkageError while performing UserRequest:hudson.maven.Maven3Builder@64dae73d java.lang.LinkageError: loader constraint violation: loader org.codehaus.plexus.classworlds.realm.ClassRealm @6acbcfc0 wants to load interface org.slf4j.Logger. A different interface with the same name was previously loaded by org.codehaus.plexus.classworlds.realm.ClassRealm @27bc2616. (org.slf4j.Logger is in unnamed module of loader org.codehaus.plexus.classworlds.realm.ClassRealm @27bc2616, parent loader 'app') at java.base/java.lang.ClassLoader.defineClass1(Native Method) at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1017) at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174) at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:555) at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:458) at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:452) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:451) at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClassFromSelf(ClassRealm.java:401) at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:42) at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271) at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:247) at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239) at org.apache.maven.cli.event.ExecutionEventLogger.<init>(ExecutionEventLogger.java:69) at hudson.maven.util.ExecutionEventLogger.<init>(ExecutionEventLogger.java:65) at hudson.maven.Maven3Builder$MavenExecutionListener.<init>(Maven3Builder.java:375) at hudson.maven.Maven3Builder$JenkinsEventSpy.<init>(Maven3Builder.java:199) at hudson.maven.Maven3Builder.call(Maven3Builder.java:119) at hudson.maven.Maven3Builder.call(Maven3Builder.java:70) at hudson.remoting.UserRequest.perform(UserRequest.java:211) at hudson.remoting.UserRequest.perform(UserRequest.java:54) at hudson.remoting.Request$2.run(Request.java:377) at hudson.remoting.InterceptingExecutorService.lambda$wrap$0(InterceptingExecutorService.java:78) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829) ERROR: Failed to parse POMs java.io.IOException: Remote call on Channel to Maven [/etc/alternatives/jre_11_openjdk/bin/java, -Xmx8192m, -XX:+UseParallelGC, -Duser.language=en, -Duser.country=GB, -verbose:gc, -cp, /var/lib/jenkins/maven35-agent.jar:/opt/maven/boot/plexus-classworlds-2.5.2.jar:/opt/maven/conf/logging, jenkins.maven3.agent.Maven35Main, /opt/maven/, /opt/swarm-client-3.39.jar, /var/lib/jenkins/maven35-interceptor.jar, /var/lib/jenkins/maven3-interceptor-commons.jar, 46713] failed at hudson.remoting.Channel.call(Channel.java:1004) at hudson.maven.ProcessCache$MavenProcess.call(ProcessCache.java:161) at hudson.maven.MavenModuleSetBuild$MavenModuleSetBuildExecution.doRun(MavenModuleSetBuild.java:877) at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:526) at hudson.model.Run.execute(Run.java:1900) at hudson.maven.MavenModuleSetBuild.run(MavenModuleSetBuild.java:543) at hudson.model.ResourceController.execute(ResourceController.java:107) at hudson.model.Executor.run(Executor.java:449) Caused by: java.lang.LinkageError: loader constraint violation: loader org.codehaus.plexus.classworlds.realm.ClassRealm @6acbcfc0 wants to load interface org.slf4j.Logger. A different interface with the same name was previously loaded by org.codehaus.plexus.classworlds.realm.ClassRealm @27bc2616. (org.slf4j.Logger is in unnamed module of loader org.codehaus.plexus.classworlds.realm.ClassRealm @27bc2616, parent loader 'app') at java.base/java.lang.ClassLoader.defineClass1(Native Method) at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1017) at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174) at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:555) at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:458) at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:452) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:451) at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClassFromSelf(ClassRealm.java:401) at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:42) at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271) at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:247) at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239) at org.apache.maven.cli.event.ExecutionEventLogger.<init>(ExecutionEventLogger.java:69) at hudson.maven.util.ExecutionEventLogger.<init>(ExecutionEventLogger.java:65) at hudson.maven.Maven3Builder$MavenExecutionListener.<init>(Maven3Builder.java:375) at hudson.maven.Maven3Builder$JenkinsEventSpy.<init>(Maven3Builder.java:199) at hudson.maven.Maven3Builder.call(Maven3Builder.java:119) at hudson.maven.Maven3Builder.call(Maven3Builder.java:70) at hudson.remoting.UserRequest.perform(UserRequest.java:211) at hudson.remoting.UserRequest.perform(UserRequest.java:54) at hudson.remoting.Request$2.run(Request.java:377) at hudson.remoting.InterceptingExecutorService.lambda$wrap$0(InterceptingExecutorService.java:78) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829) Suppressed: hudson.remoting.Channel$CallSiteStackTrace: Remote call to Channel to Maven [/etc/alternatives/jre_11_openjdk/bin/java, -Xmx8192m, -XX:+UseParallelGC, -Duser.language=en, -Duser.country=GB, -verbose:gc, -cp, /var/lib/jenkins/maven35-agent.jar:/opt/maven/boot/plexus-classworlds-2.5.2.jar:/opt/maven/conf/logging, jenkins.maven3.agent.Maven35Main, /opt/maven/, /opt/swarm-client-3.39.jar, /var/lib/jenkins/maven35-interceptor.jar, /var/lib/jenkins/maven3-interceptor-commons.jar, 46713] at hudson.remoting.Channel.attachCallSiteStackTrace(Channel.java:1784) at hudson.remoting.UserRequest$ExceptionResponse.retrieve(UserRequest.java:356) at hudson.remoting.Channel.call(Channel.java:1000) at hudson.maven.ProcessCache$MavenProcess.call(ProcessCache.java:161) at hudson.maven.MavenModuleSetBuild$MavenModuleSetBuildExecution.doRun(MavenModuleSetBuild.java:877) at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:526) at hudson.model.Run.execute(Run.java:1900) at hudson.maven.MavenModuleSetBuild.run(MavenModuleSetBuild.java:543) at hudson.model.ResourceController.execute(ResourceController.java:107) at hudson.model.Executor.run(Executor.java:449) channel stopped [CucumberReport] Using Cucumber Reports version 5.6.1 [CucumberReport] JSON report directory is "get-automated-testing/target" [CucumberReport] Copied 0 properties files from workspace "/var/lib/jenkins/workspace/Aurora-QA-Integration Testing-E2E/get-automated-testing/target" to reports directory "/var/lib/jenkins/jobs/Aurora-QA-Integration Testing-E2E/builds/1708/cucumber-html-reports/.cache" [CucumberReport] Copied 0 files from workspace "/var/lib/jenkins/workspace/Aurora-QA-Integration Testing-E2E/get-automated-testing/target" to reports directory "/var/lib/jenkins/jobs/Aurora-QA-Integration Testing-E2E/builds/1708/cucumber-html-reports/.cache" [CucumberReport] Processing 0 json files: [CucumberReport] Missing report result - report was not successfully completed [CucumberReport] Build status is changed to null Finished: FAILURE
POM依赖代码
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> </dependency>
解决方案
1. 调整Swarm Client类加载策略
启动Swarm Client时添加JVM参数,强制其优先使用系统类加载器加载slf4j相关类,避免与Maven的类加载器冲突:
java -Dswarm.client.classloader.parent-first=true -jar /opt/swarm-client-3.39.jar [其他启动参数]
或者将Swarm Client依赖的slf4j jar包移至系统JRE的lib/ext目录,让系统类加载器统一管理。
2. 统一POM中slf4j依赖版本并排除冲突
在POM中添加dependencyManagement统一slf4j版本,同时排除所有传递依赖的slf4j,并添加log4j与slf4j的桥接依赖:
<dependencyManagement> <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.36</version> <!-- 选择与Swarm Client兼容的版本 --> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- 原有log4j依赖 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j.version}</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> <!-- 添加log4j到slf4j的桥接器 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j.version}</version> <scope>runtime</scope> </dependency> <!-- 显式声明slf4j-api并设置为provided,避免重复加载 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.36</version> <scope>provided</scope> </dependency> </dependencies>
3. 升级Swarm Client版本
Swarm Client 3.39可能与Jenkins 2.375.1存在兼容性问题,升级至与目标Jenkins版本匹配的Swarm Client(如4.x系列),新版本通常会修复类加载冲突等兼容性问题。
4. 修改Maven Agent启动参数
在Jenkins全局配置的Maven设置中,添加JVM参数强制Maven使用统一类加载器:
-Dmaven.classworlds.conf=/path/to/custom-classworlds.conf
在自定义的classworlds.conf中配置slf4j类的加载优先级,示例配置:
main is org.apache.maven.cli.MavenCli from plexus.core set realms.default = system, plexus.core, extensions [system] load *.jar from ${maven.home}/lib load org.slf4j.* from ${maven.home}/lib/slf4j-api-1.7.36.jar [plexus.core] load *.jar from ${maven.home}/boot
5. 统一Jenkins节点依赖版本
确保Jenkins服务器和所有Agent节点上的slf4j相关jar包版本一致,避免跨节点的依赖版本差异导致类加载冲突。
内容的提问来源于stack exchange,提问作者NaushadNaleer

