Java 9+环境下基于javassist的javaagent模块化访问异常问题
问题解决方案
根因分析
你的问题由两个错误配置共同导致:
- Java 9+模块化机制限制:属于
java.base命名模块的java.lang.Error,默认无法访问bootstrap类加载器加载的未命名模块中的代理类,即便添加了--add-reads指定自定义模块也无效,因为你把代理包放在了bootclasspath下,实际加载到的是未命名模块的类,不是你配置的sg.agent命名模块。 - 重复类加载冲突:你同时将代理包配置到
-Xbootclasspath/a和--module-path下,导致同一个代理类被bootstrap类加载器和应用类加载器各加载一次,最终触发Jetty启动时的重复类定义报错。
修复步骤
步骤1:清理冗余启动参数
删除以下错误配置的启动参数:
--module-path path-to-agent-jar-folder--add-modules sg.agent--add-modules java.base
保留两个基础参数:-Xbootclasspath/a:"path-to-agent.jar"-javaagent:path-to-agent.jar
步骤2:添加正确的模块化权限参数
新增启动参数--add-reads java.base=ALL-UNNAMED,直接授予java.base模块对bootstrap类加载器持有的所有未命名模块类的访问权限,适配你将代理包放在bootclasspath的加载逻辑。
步骤3:修复Javassist类找不到问题
你当前栈中Javassist编译报错,是因为Javassist默认的类池未加载到bootstrap路径下的代理类,需要在ErrorClassTransformer.transform方法中,执行插桩代码前手动补充类路径:
ClassPool classPool = ClassPool.getDefault(); // 追加bootstrap类加载器的类路径,null代表bootstrap加载器 classPool.appendClassPath(new LoaderClassPath(null));
步骤4:清理Manifest冗余配置
删除代理Jar包Manifest文件中的以下配置项,这些模块化配置只适用于命名模块加载场景,和你当前的bootclasspath加载逻辑冲突:
Automatic-Module-Name: sg.agentAdd-Exports: module/packageAdd-Opens: module/package
步骤5:验证最终启动参数
调整后的完整启动参数仅保留3项:
-Xbootclasspath/a:"path-to-agent.jar" -javaagent:path-to-agent.jar --add-reads java.base=ALL-UNNAMED
启动后即可正常完成java.lang.Error的插桩,也不会出现Jetty重复类加载的问题。
内容的提问来源于stack exchange,提问作者Srinivas
相关产品推荐
相关产品推荐

