基于Instrument API的Agent无法检测SpringBoot未扫描的Chap03类
问题分析与解决
核心原因
你遇到的问题本质是类加载时机导致的:
- 当Chap03没有@Configuration这类注解时,它既没被Spring上下文扫描到,也没被其他业务代码引用,JVM会采用延迟加载策略,根本不会加载这个类,所以你的Transformer自然捕获不到。
- premain里的
Class.forName失败,是因为Agent的类加载器(系统类加载器)和SpringBoot应用的类加载器(LaunchedURLClassLoader)不是同一个,系统类加载器找不到应用包下的类。
具体解决方案
1. 强制触发类加载(最简单直接)
在SpringBoot主类里显式引用Chap03,哪怕只是声明一个无用的变量,让JVM在启动时加载该类:
@SpringBootApplication public class YourSpringBootMain { // 声明变量触发类加载 private static Chap03 dummy = new Chap03(); public static void main(String[] args) { SpringApplication.run(YourSpringBootMain.class, args); } }
2. 调整Agent的类加载逻辑
在premain中,先添加Transformer,再尝试用应用类加载器加载目标类:
public static void premain(String agentArgs, Instrumentation instrumentation) { Banner.send(agentArgs); ConfigRead configRead = new ConfigRead(); // 先添加Transformer,再尝试加载类 instrumentation.addTransformer(new Chap03Transformer()); // 获取应用类加载器(SpringBoot的LaunchedURLClassLoader) ClassLoader appClassLoader = Thread.currentThread().getContextClassLoader(); try { // 用应用类加载器加载目标类 Class.forName("com.dummy.jdbcserver.example_asm.Chap03", true, appClassLoader); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
注意:必须先添加Transformer再加载类,否则加载类的时候Transformer还没生效。
3. 利用Spring的扫描机制
除了@Configuration,你也可以给Chap03加更轻量的注解比如@Component,同时确保SpringBoot的@ComponentScan覆盖该类所在的包:
@Component // 替换@Configuration,更轻量 public class Chap03 { // ... 原有代码 }
这样Spring上下文启动时会扫描并加载该类,Transformer就能捕获到。
4. 遍历已加载类并触发重转换
如果类已经被加载(比如启动后动态加载),可以用Instrumentation的retransformClasses方法触发转换:
// 在premain或者后续JMX线程中执行 for (Class<?> clazz : instrumentation.getAllLoadedClasses()) { if (clazz.getName().contains("Chap03")) { try { instrumentation.retransformClasses(clazz); } catch (Exception e) { e.printStackTrace(); } } }
这个方法适合类已经被加载但没被转换的场景。
额外注意点
- Transformer中的
className是用斜杠分隔的(比如com/dummy/jdbcserver/example_asm/Chap03),你的contains("Chap03")逻辑没问题,但可以更精准:className.endsWith("/Chap03") - 确保Agent的jar包被正确配置到SpringBoot的启动参数中(比如
-javaagent:your-agent.jar)
内容的提问来源于stack exchange,提问作者Leon
相关产品推荐
相关产品推荐

