博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java字节码3-使用ByteBuddy实现一个Java-Agent
阅读量:6997 次
发布时间:2019-06-27

本文共 4215 字,大约阅读时间需要 14 分钟。

  hot3.png

一、概述

在前面两节中,我们实现了Agent,但是其无论在使用方式和功能上面都有一定的局限性。本文我们借助字节码工具ByteBuddy,写出高级的Agent。

ByteBuddy不仅仅是为了生成Java-Agent,它提供的API甚至可以改变重写一个Java类,本文我们使用其API实现和第二节一样的功能,给目标类中的函数统计其调用耗时。

二、实现

1、修改pom.xml
本节和上节的不同点,主要有两个。一个是引入ByteBuddy的依赖,另一个是需要将ByteBuddy的包通过shade打入到Agent中。下面只截取关键代码:

net.bytebuddy
byte-buddy
1.5.7
net.bytebuddy
byte-buddy-agent
1.5.7
org.apache.maven.plugins
maven-shade-plugin
package
shade
javassist:javassist:jar:
net.bytebuddy:byte-buddy:jar:
net.bytebuddy:byte-buddy-agent:jar:

2、实现一个Agent

与之前相同的是,这里仍然是在premain处进行处理。通过AgentBuilder方法,生成一个Agent。这里有两点需要特别说明:其一是在AgentBuilder.type处,这里可以指定需要拦截的类;其二是在builder.method处,这里可以指定需要拦截的方法。当然其API支持各种isStatic、isPublic等等一系列方式。

public class MyAgent {    public static void premain(String agentArgs, Instrumentation inst) {        System.out.println("this is an perform monitor agent.");        AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {            @Override            public DynamicType.Builder
transform(DynamicType.Builder
builder, TypeDescription typeDescription, ClassLoader classLoader) { return builder .method(ElementMatchers.
any()) // 拦截任意方法 .intercept(MethodDelegation.to(TimeInterceptor.class)); // 委托 } }; AgentBuilder.Listener listener = new AgentBuilder.Listener() { @Override public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, DynamicType dynamicType) {} @Override public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) { } @Override public void onError(String typeName, ClassLoader classLoader, JavaModule module, Throwable throwable) { } @Override public void onComplete(String typeName, ClassLoader classLoader, JavaModule module) { } }; new AgentBuilder .Default() .type(ElementMatchers.nameStartsWith("com.example.demo")) // 指定需要拦截的类 .transform(transformer) .with(listener) .installOn(inst); }}

3、实现一个用来委托的Interceptor

在上一步实现Transformer的过程中,委托了一个TimeInterceptor.class。下面是其实现方式,整个的try语句是原有的代码执行,我们在之前打了时间戳,并在其结束后,计算并打印了其调用耗时。

public class TimeInterceptor  {    @RuntimeType    public static Object intercept(@Origin Method method,                                   @SuperCall Callable
callable) throws Exception { long start = System.currentTimeMillis(); try { // 原有函数执行 return callable.call(); } finally { System.out.println(method + ": took " + (System.currentTimeMillis() - start) + "ms"); } }}

三、运行

这里需要注意的是,我们定义的包路径要和Agent中定义的相同,否则Agent无法Hook到这个类及其方法。

package com.example.demo;public class AgentTest {    private void fun1() throws Exception {        System.out.println("this is fun 1.");        Thread.sleep(500);    }    private void fun2() throws Exception {        System.out.println("this is fun 2.");        Thread.sleep(500);    }    public static void main(String[] args) throws Exception {        AgentTest test = new AgentTest();        test.fun1();        test.fun2();    }}

结果:

this is an perform monitor agent.this is fun 1.private void com.example.demo.AgentTest.fun1() throws java.lang.Exception: took 501msthis is fun 2.private void com.example.demo.AgentTest.fun2() throws java.lang.Exception: took 500mspublic static void com.example.demo.AgentTest.main(java.lang.String[]) throws java.lang.Exception: took 1001ms

 

转载于:https://my.oschina.net/voole/blog/2962624

你可能感兴趣的文章
IO流
查看>>
第二十四章:页面导航(四)
查看>>
数字对讲系统开发札记(前端linux c 后端 c#)
查看>>
海外共享公寓品牌Tripalink完成A轮融资,险峰长青领投
查看>>
阿里在使用一种更灵活的软件集成发布模式
查看>>
自己实现一个StringBuffer
查看>>
SpringBoot使用Nacos配置中心
查看>>
星矿科技完成千万元融资,专注明星IP价值商业化
查看>>
SOP 1.2.0 发布,开放平台解决方案项目
查看>>
Element 2.6.3 发布,基于 Vue 2.0 的桌面端组件库
查看>>
丰田研发智能汽车FV2,可利用肢体进行操控
查看>>
基于kubeadm的kubernetes高可用集群部署
查看>>
定位「数字化助手」,腾讯想用服务创新助力产业智慧升级
查看>>
golang之sync.Mutex互斥锁源码分析
查看>>
SAP增强的PA教材内容
查看>>
jQuery系列 第八章 jQuery框架Ajax模块
查看>>
OpenCV中原始图像加载与保存压缩技巧
查看>>
MySQL 8复制性能的增强
查看>>
C#使用Xamarin开发可移植移动应用(3.Xamarin.Views控件)附源码
查看>>
Java 模拟基于UDP的Socket通信
查看>>