JMeter引入自定义Jar引发Groovy依赖冲突问题及解决咨询
问题描述
我有一个Java项目,依赖包含rest-assured(4.1.2)在内的其他Maven项目,该组件依赖Groovy(2.5.8)。为在JMeter中使用该项目功能,我将其Jar放入JMeter的lib目录,但运行JMeter时无法加载JSR223 Sampler,日志显示依赖冲突:JMeter期望Groovy 3.0.11,却因自定义Jar加载了Groovy 2.5.8;若升级rest-assured至最新版,自定义Jar则会引入Groovy 4.0.6。
错误日志
2023-02-24 13:21:21,009 ERROR o.a.j.JMeter: Uncaught exception in thread Thread[AWT-EventQueue-0,6,main] java.lang.ExceptionInInitializerError: null at java.lang.J9VMInternals.ensureError(J9VMInternals.java:206) ~[?:?] at java.lang.J9VMInternals.recordInitializationFailure(J9VMInternals.java:195) ~[?:?] at org.codehaus.groovy.jsr223.GroovyScriptEngineFactory.getLanguageVersion(GroovyScriptEngineFactory.java:95) ~[groovy-jsr223-3.0.11.jar:3.0.11] at org.apache.jmeter.util.JSR223BeanInfoSupport.<clinit>(JSR223BeanInfoSupport.java:69) ~[ApacheJMeter_core.jar:5.5] at java.lang.J9VMInternals.newInstanceImpl(Native Method) ~[?:?] at java.lang.Class.newInstance(Class.java:2338) ~[?:?] at com.sun.beans.finder.InstanceFinder.instantiate(InstanceFinder.java:98) ~[?:?] at com.sun.beans.finder.InstanceFinder.find(InstanceFinder.java:66) ~[?:?] at com.sun.beans.finder.BeanInfoFinder.find(BeanInfoFinder.java:41) ~[?:?] at java.beans.Introspector.findExplicitBeanInfo(Introspector.java:467) ~[?:?] at java.beans.Introspector.<init>(Introspector.java:417) ~[?:?] at java.beans.Introspector.getBeanInfo(Introspector.java:195) ~[?:?] at org.apache.jmeter.testbeans.gui.TestBeanGUI.<init>(TestBeanGUI.java:162) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.GuiPackage.getGuiFromCache(GuiPackage.java:417) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.GuiPackage.getGui(GuiPackage.java:266) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.GuiPackage.getGui(GuiPackage.java:237) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.tree.JMeterTreeModel.addComponent(JMeterTreeModel.java:160) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.tree.JMeterTreeModel.addSubTree(JMeterTreeModel.java:131) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.tree.JMeterTreeModel.addSubTree(JMeterTreeModel.java:131) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.tree.JMeterTreeModel.addSubTree(JMeterTreeModel.java:131) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.tree.JMeterTreeModel.addSubTree(JMeterTreeModel.java:123) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.GuiPackage.addSubTree(GuiPackage.java:554) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.action.Load.insertLoadedTree(Load.java:199) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.action.Load.loadProjectFile(Load.java:130) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.action.Load.loadProjectFile(Load.java:101) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.action.LoadRecentProject.doActionAfterCheck(LoadRecentProject.java:71) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.action.AbstractActionWithNoRunningTest.doAction(AbstractActionWithNoRunningTest.java:44) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.action.ActionRouter.performAction(ActionRouter.java:87) ~[ApacheJMeter_core.jar:5.5] at org.apache.jmeter.gui.action.ActionRouter.lambda$actionPerformed$0(ActionRouter.java:69) ~[ApacheJMeter_core.jar:5.5] at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313) ~[?:?] at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770) ~[?:?] at java.awt.EventQueue$4.run(EventQueue.java:721) ~[?:?] at java.awt.EventQueue$4.run(EventQueue.java:715) ~[?:?] at java.security.AccessController.doPrivileged(AccessController.java:717) ~[?:?] at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) ~[?:?] at java.awt.EventQueue.dispatchEvent(EventQueue.java:740) ~[?:?] at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) ~[?:?] at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) ~[?:?] at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) ~[?:?] at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) ~[?:?] at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) ~[?:?] at java.awt.EventDispatchThread.run(EventDispatchThread.java:90) ~[?:?] Caused by: groovy.lang.GroovyRuntimeException: Conflicting module versions. Module [groovy-xml is loaded in version 4.0.6 and you are trying to load version 3.0.11 at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl$DefaultModuleListener.onModule(MetaClassRegistryImpl.java:534) ~[custom-framework-1.0-SNAPSHOT-jar-with-dependencies.jar:?]
解决方案
1. 构建自定义Jar时排除Groovy依赖(推荐)
修改项目的pom.xml,在所有依赖Groovy的组件(如rest-assured)中排除Groovy相关模块,让自定义Jar不携带Groovy类,直接复用JMeter自带的Groovy版本:
<dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>4.1.2</version> <exclusions> <exclusion> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> </exclusion> <exclusion> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-xml</artifactId> </exclusion> <exclusion> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-json</artifactId> </exclusion> <!-- 按需排除所有Groovy子模块 --> </exclusions> </dependency>
执行mvn clean package生成不包含Groovy的Jar,放入JMeter的lib目录即可。
2. 升级JMeter适配更高版本Groovy
JMeter 5.5默认依赖Groovy 3.0.11,若你升级到JMeter 5.6及以上版本,它原生支持Groovy 4.x。操作步骤:
- 下载对应版本的JMeter;
- 删除JMeter
lib目录下所有groovy-*.jar文件; - 放入Groovy 4.0.6的完整Jar包(需包含所有必要子模块);
- 确保自定义Jar使用Groovy 4.0.6作为依赖重新构建。
注意:升级JMeter需验证核心功能(如取样器、断言)是否正常工作。
3. 使用Maven Shadow插件隔离Groovy依赖
通过重命名自定义Jar中的Groovy包路径,让它和JMeter的Groovy类处于不同命名空间,避免冲突。在pom.xml中添加Shadow插件配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <relocations> <relocation> <pattern>org.codehaus.groovy</pattern> <shadedPattern>com.yourcompany.shaded.groovy</shadedPattern> </relocation> </relocations> </configuration> </execution> </executions> </plugin>
执行mvn clean package生成重命名后的Jar,放入JMeter目录使用。
4. 调整Jar存放目录(备选)
将自定义Jar放入JMeter的lib/ext目录而非lib目录,利用JMeter的类加载顺序(lib目录优先加载,lib/ext后加载)尝试规避冲突,但此方法不保证对所有场景有效。
内容的提问来源于stack exchange,提问作者Koranke

