提示 NoClassDefFoundError 。 还是说需要其他方式
public void execute(Runnable var1) {
// 编译增加的代码
MDC.setContextMap((Map)MDCInheritableThreadLocal.get());
// 本身的源码
if (var1 == null) {
NullPointerException var10000 = new NullPointerException();
System.out.println("end");
throw var10000;
} else {
int var2 = this.ctl.get();
if (workerCountOf(var2) < this.corePoolSize) {
if (this.addWorker(var1, true)) {
System.out.println("end");
return;
}
var2 = this.ctl.get();
}
// ...
}
会提示 NoClassDefFoundError: fun/MDCInheritableThreadLocal
1
wsxyeah 2021-01-25 20:47:15 +08:00 via iPhone
这些东西是用户机器上的,除非你打包一个 jre 进去
|
2
gengzi OP @wsxyeah 我在启用前使用 Agent,修改 jdk ThreadPoolExecutor execute 的方法,引入的 jar 应该会在运行时加载吧。
|
3
ffutop 2021-01-26 09:02:53 +08:00 1
ThreadPoolExecutor 是被 Bootstrap ClassLoader 加载的。它的加载路径不包括你自定义的 MDCInheritableThreadLocal 。
可以用 -Xbootclasspath 指定 Bootstrap 加载特定 Jar 包 或者在 MANIFEST.MF 用 Boot-Class-Path 声明 Jar 包路径 |
4
kingfalse 2021-01-26 09:38:14 +08:00 via Android
试试 javassist
|
5
fantastM 2021-01-26 10:48:36 +08:00
在启动参数里用 -javaagent 的话,确实是如 #3 说的类加载问题。可以用 arthas 的 sc 、classloader 之类的命令来查看类的加载情况
|
7
gengzi OP |
8
fantastM 2021-01-27 02:59:44 +08:00 1
简单回答:可以在 agent 中自定义类加载器,避免遵循 Java 类加载器中的双亲委派模型。
详细回答: JVM 加载类是按照双亲委派模型来执行的,每个类都会优先委托给父类加载器来加载,当父类加载器无法加载类的时候再由子类加载器来加载,因此在 JVM 中加载的类会有一种层级关系。 在你的例子中 `ThreadPoolExecutor` 会由 BootStrap ClassLoader 加载,参数 -javaagent 指定的 baselog.jar 包默认会由 System ClassLoader 加载,所以你一开始描述的问题原因是:`ThreadPoolExecutor` 类在被 BootStrap ClassLoader 加载之后链接的时候,无法找到需要被 System ClassLoader 加载的 baselog.jar 包里的 `MDCInheritableThreadLocal`。(注意这个问题是发生在链接阶段,这也是 JVM 为什么抛了 `NoClassDefFoundError` 而不是 `ClassNotFoundException` 的原因) 然后你将 baselog.jar 包指定为由 BootStrap ClassLoader 加载,这样的话,`ThreadPoolExecutor` 类在被 BootStrap ClassLoader 加载、链接、初始化的时候,就可以找到同样是被 BootStrap ClassLoader 加载的 `MDCInheritableThreadLocal` 了。 你在 #7 里说的事情,我理解为是你在 baselog.jar 包里用到了「项目中的引入的 jar 」(可能是 Spring 之类的吧),这部分包不由是 BootStrap ClassLoader 加载的,可能是 System ClassLoader,也可能是 Tomcat 的 Webapp ClassLoader,所以自然也会有 `ClassNotFoundException` 的问题。解决方案的话,我不建议把这类包也指定为由 BootStrap ClassLoader 来加载,更好的解决方案是自定义类加载机制,破坏一下 Java 类加载器中的双亲委派模型。 具体实现的话,可以借鉴一些分布式追踪 APM 系统,它们在采集应用的数据时候,使用的无侵入式方案也是 javaagent,也会对项目中的一些代码做改造。 一些可供查阅的资料: https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html |