【Agent】ByteBuddy 增加方法执行耗时
1 前言
上节我们使用javassist字节码增强的方式,来监控方法程序的执行耗时。这节我们再用一个字节码操作工具ByteBuddy来帮助我们实现更完善的监控程序。
2 Java agent
2.1 ByteBuddy 是什么
Byte Buddy是一个字节码生成和操作库,用于在Java应用程序运行时创建和修改Java类,而无需编译器的帮助。
除了Java类库附带的代码生成实用程序外,Byte Buddy还允许创建任意类,并且不限于实现用于创建运行时代理的接口。
此外,Byte Buddy提供了一种方便的API,可以使用Java代理或在构建过程中手动更改类。
无需理解字节码指令,即可使用简单的 API 就能很容易操作字节码,控制类和方法。
已支持Java 11,库轻量,仅取决于Java字节代码解析器库ASM的访问者API,它本身不需要任何其他依赖项。
比起JDK动态代理、cglib、Javassist,Byte Buddy在性能上具有一定的优势。
就像它的官网介绍;
Byte Buddy 是一个代码生成和操作库,用于在 Java 应用程序运行时创建和修改 Java 类,而无需编译器的帮助。除了 Java 类库附带的代码生成实用程序外,Byte Buddy 还允许创建任意类,并且不限于实现用于创建运行时代理的接口。
此外,Byte Buddy 提供了一种方便的 API,可以使用 Java 代理或在构建过程中手动更改类。
- 无需理解字节码指令,即可使用简单的 API 就能很容易操作字节码,控制类和方法。
- 已支持Java 11,库轻量,仅取决于Java字节代码解析器库ASM的访问者API,它本身不需要任何其他依赖项。
- 比起JDK动态代理、cglib、Javassist,Byte Buddy在性能上具有一定的优势。
另外关于字节码的增强工具的对比:
对比 | ASM | Javassist | JDK Proxy | Cglib | ByteBuddy |
---|---|---|---|---|---|
起源时间 | 2002 | 1999 | 2000 | 2011 | 2014 |
包大小 | 130KB (版本9.3) | 788KB (版本3.28.0-GA) | 3.7MB (版本1.10.19) | ||
增强方式 | 字节码指令 | 字节码指令和源码(注:源码文本) | 源码 | 源码 | 源码 |
源码编译 | NA | 不支持 | 支持 | 支持 | 支持 |
agent支持 | 支持 | 支持 | 不支持,依赖框架 | 不支持,依赖框架 | 支持 |
性能 | 高 | 中 | 低 | 中 | 中 |
维护状态 | 是 | 是 | 停止升级 | 停止维护 | 活跃 |
优点 | 超高性能,应用场景广泛 | 同时支持字节码指令和源码两种增强方式 | JDK原生类库支持 | 零侵入,提供良好的API扩展编程 | |
缺点 | 字节码指令对应用开发者不友好 | 场景非常局限,只适用于Java接口 | 已经不再维护,对于新版JDK17+支持不好,官网建议切换到ByteBuddy | ||
应用场景 | 小,高性能,广泛用于语言级别 | 广泛用于框架场景 | 广泛用于Trace场景 |
2.2 尝试
首先加入依赖:
<dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> <version>1.8.20</version> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> <version>1.8.20</version> </dependency> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> <configuration> <artifactSet> <includes> <include>javassist:javassist:jar:</include> <include>net.bytebuddy:byte-buddy:jar:</include> <include>net.bytebuddy:byte-buddy-agent:jar:</include> </includes> </artifactSet> </configuration> </plugin>
MyAgent.java
/** * @author: kuku * @description */ public class MyAgent { /** * JVM 首先尝试在代理类上调用以下方法 * @param agentArgs * @param inst */ public static void premain(String agentArgs, Instrumentation inst) { AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> { return builder .method(ElementMatchers.any()) // 拦截任意方法 .intercept(MethodDelegation.to(MethodCostTime.class)); // 委托 }; AgentBuilder.Listener listener = new AgentBuilder.Listener() { @Override public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) { } @Override public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) { } @Override public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) { } @Override public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) { } @Override public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) { } }; new AgentBuilder .Default() .type(ElementMatchers.nameStartsWith("com.virtuous")) // 指定需要拦截的类 .transform(transformer) .with(listener) .installOn(inst); } /** * 如果代理类没有实现上面的方法,那么 JVM 将尝试调用该方法 * @param agentArgs */ public static void premain(String agentArgs) { System.out.println("premain方法2" + agentArgs); } }
MethodCostTime.java
/** * @author kuku */ public class MethodCostTime { @RuntimeType public static Object intercept(@Origin Method method, @SuperCall Callable<?> callable) throws Exception { long start = System.nanoTime(); try { // 原有函数执行 return callable.call(); } finally { System.out.println(method + " 方法耗时: " + (System.nanoTime() - start) + "ns"); } } }
测试执行效果:
3 小结
好啦,本节就到这里,有理解不对的地方欢迎指正哈。
分类:
源码 / Agent
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2023-06-06 【Redis】【持久化】RDB 快照是怎么实现的?
2023-06-06 【Redis】【持久化】AOF 持久化是怎么实现的?
2023-06-06 【Redis】Redis 数据类型详解
2023-06-06 【网络基础】Linux 系统是如何收发网络包的?
2023-06-06 【网络基础】键入网址到网页显示,期间发生了什么?
2023-06-06 【网络基础】TCP/IP 网络模型有哪几层?