如何为类添加静态方法并委托至已有方法?附Agent及Transformer代码
实现通过Byte Buddy为SpringApplication添加静态委托方法
你已经搭好了Java Agent的基础框架,接下来咱们把给org.springframework.boot.SpringApplication添加静态委托方法的功能补全。核心思路是用Byte Buddy的字节码增强能力,新增一个静态run方法,并把它的调用转发到SpringApplication已有的原生run方法上。
完整的SpringApplicationTransformer实现
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.bind.annotation.AllArguments; import net.bytebuddy.implementation.bind.annotation.Origin; import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.agent.builder.AgentBuilder; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class SpringApplicationTransformer implements AgentBuilder.Transformer { @Override public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, java.lang.module.Module module) { try { // 定义和原生方法签名一致的静态run方法 builder = builder .defineMethod("run", Object.class, Modifier.PUBLIC | Modifier.STATIC) .withParameter(Class.class, "primarySource") .withParameter(String[].class, "args") .intercept(MethodDelegation.to(SpringApplicationDelegate.class)); return builder; } catch (Exception e) { throw new RuntimeException("Failed to inject static run method into SpringApplication", e); } } // 委托类:负责把新方法的调用转发到原生run方法 public static class SpringApplicationDelegate { public static Object run(@Origin Method method, @AllArguments Object[] args) throws Exception { // 通过反射获取SpringApplication的原生静态run方法 Method originalRunMethod = Class.forName("org.springframework.boot.SpringApplication") .getMethod("run", Class.class, String[].class); // 调用原生方法并返回结果 return originalRunMethod.invoke(null, args); } } }
关键细节解释
- 定义新静态方法:用
defineMethod声明一个public static的run方法,返回值设为Object(兼容原生方法返回的ConfigurableApplicationContext),参数列表和SpringApplication原生的run(Class<?> primarySource, String... args)完全对齐。 - 方法拦截与转发:通过
MethodDelegation.to()把新方法的调用交给委托类处理,这是Byte Buddy实现方法增强的核心方式。 - 委托类逻辑:
@AllArguments Object[] args:自动捕获调用新方法时传入的所有参数- 用反射拿到原生的静态
run方法,因为原生方法本身是静态的,所以invoke时第一个参数传null - 最后把原生方法的执行结果返回,保证新方法和原生方法的行为完全一致
额外注意事项
- 依赖准备:确保项目引入了Byte Buddy的核心依赖,比如Maven配置:
<dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> <version>1.14.11</version> <!-- 建议使用最新稳定版 --> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> <version>1.14.11</version> </dependency>
- Agent打包配置:把Agent类和Transformer类打包成jar时,需要在
MANIFEST.MF中指定Premain入口:
Premain-Class: com.your.package.Agent Can-Redefine-Classes: true
- 调用验证:完成后你就可以像调用原生方法一样使用这个新增的静态方法,效果完全一致:
SpringApplication.run(YourBootApp.class, args);
内容的提问来源于stack exchange,提问作者Dave Syer
相关产品推荐
相关产品推荐

