基于JavaAgent的全链路监控三《ByteBuddy操作监控方法字节码》

简介: 在第二章中我们已经可以监控方法执行耗时,虽然它能完成我们一些基本需要,但是为了增强代码的扩展性,我们需要使用字节码操作工具ByteBuddy来帮助我们实现更完善的监控程序。

8.jpg

案例简述

在第二章中我们已经可以监控方法执行耗时,虽然它能完成我们一些基本需要,但是为了增强代码的扩展性,我们需要使用字节码操作工具ByteBuddy来帮助我们实现更完善的监控程序。

Byte Buddy is a code generation and manipulation library for creating and modifying Java classes during the runtime of a Java application and without the help of a compiler. Other than the code generation utilities that ship with the Java Class Library, Byte Buddy allows the creation of arbitrary classes and is not limited to implementing interfaces for the creation of runtime proxies. Furthermore, Byte Buddy offers a convenient API for changing classes either manually, using a Java agent or during a build.

环境准备

1、IntelliJ IDEA Community Edition

2、jdk1.8.0_45 64位

配置信息

(路径相关修改为自己的)

1、配置位置:Run/Debug Configurations -> VM options

2、配置内容:-javaagent:E:\itstack\GIT\itstack.org\itstack-demo-agent\itstack-demo-agent-03\target\itstack-demo-agent-03-1.0.0-SNAPSHOT.jar=testargs

代码示例

itstack-demo-agent-03
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── org.itstack.demo.agent
    │   │       ├── MethodCostTime.java
    │   │       └── MyAgent.java
    │   └── resources
    │       └── META-INF
    │           └── MANIFEST.MF
    └── test
         └── java
             └── org.itstack.demo.test
                 └── ApiTest.java

pom.xml (引入ByteBuddy并打入到Agent包中)

<properties>
    <!-- Build args -->
    <argline>-Xms512m -Xmx512m</argline>
    <skip_maven_deploy>false</skip_maven_deploy>
    <updateReleaseInfo>true</updateReleaseInfo>
    <project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
    <maven.test.skip>true</maven.test.skip>
    <!-- 自定义MANIFEST.MF -->
    <maven.configuration.manifestFile>src/main/resources/META-INF/MANIFEST.MF</maven.configuration.manifestFile>
</properties>
<dependencies>
    <dependency>
        <groupId>javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.12.1.GA</version>
        <type>jar</type>
    </dependency>
    <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>
</dependencies>
<!-- 将javassist包打包到Agent中 -->
<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>

MethodCostTime.java

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class MethodCostTime {
    @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 + " 方法耗时:" + (System.currentTimeMillis() - start) + "ms");
        }
    }
}

MyAgent.java

/**
 * javaagent
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 */
public class MyAgent {
    //JVM 首先尝试在代理类上调用以下方法
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("this is my agent:" + agentArgs);
        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("org.itstack.demo.test")) // 指定需要拦截的类
                .transform(transformer)
                .with(listener)
                .installOn(inst);
    }
    //如果代理类没有实现上面的方法,那么 JVM 将尝试调用该方法
    public static void premain(String agentArgs) {
    }
}

MANIFEST.MF

Manifest-Version: 1.0
Premain-Class: org.itstack.demo.agent.MyAgent
Can-Redefine-Classes: true

ApiTest.java

/**
 * 博客:http://itstack.org
 * 论坛:http://bugstack.cn
 * 公众号:bugstack虫洞栈  {获取学习源码}
 * create by fuzhengwei on 2019
 *
 * VM options:
 * -javaagent:E:\itstack\GIT\itstack.org\itstack-demo-agent\itstack-demo-agent-03\target\itstack-demo-agent-03-1.0.0-SNAPSHOT.jar=testargs
 */
public class ApiTest {
    public static void main(String[] args) throws InterruptedException {
        ApiTest apiTest = new ApiTest();
        apiTest.echoHi();
    }
    private void echoHi() throws InterruptedException {
        System.out.println("hi agent");
        Thread.sleep((long) (Math.random() * 500));
    }
}

测试结果

this is my agent:testargs
hi agent
private void org.itstack.demo.test.ApiTest.echoHi() throws java.lang.InterruptedException 方法耗时:329ms
public static void org.itstack.demo.test.ApiTest.main(java.lang.String[]) throws java.lang.InterruptedException 方法耗时:329ms
Process finished with exit code 0
目录
相关文章
|
7月前
|
监控 Oracle 数据可视化
深度解析JVM性能监控工具:推荐与详细用法
深度解析JVM性能监控工具:推荐与详细用法
206 0
|
Arthas Cloud Native Java
是谁在调用我?使用 arthas+jprofiler 做复杂链路分析
Arthas 是阿里巴巴开源的应用诊断利器,提供了 profiler 命令,可以生成热点火焰图。通过采样录制调用链路来做性能分析,极大提升了线上排查性能问题的效率。
是谁在调用我?使用 arthas+jprofiler 做复杂链路分析
|
5月前
|
监控 Java
JVM日志分析及工具
JVM日志分析及工具
48 0
|
6月前
|
存储 消息中间件 监控
代码级别监控:常见的全链路监控工具介绍
代码级别监控:常见的全链路监控工具介绍
|
9月前
|
监控 Java
JVM 监控
JVM 监控
129 0
|
11月前
|
Java
APM - 使用JavaAgent+Javassit 插桩C3P0
APM - 使用JavaAgent+Javassit 插桩C3P0
92 0
|
监控 安全 Oracle
JVM学习(二):JVM监控及诊断工具-命令行篇(上)
Java 作为最流行的编程语言之一,其应用性能诊断一直受到业界广泛关注。可能造成Java应用出现性能问题的因素非常多,例如线程控制、磁盘读写、数据库访问、网络I/o、垃圾收集等。想要定位这些问题,一款优秀的性能诊断工具必不可少。
218 0
JVM学习(二):JVM监控及诊断工具-命令行篇(上)
|
Arthas 存储 监控
|
运维 监控 数据可视化
Java生产环境性能监控与调优—基于JDK命令行工具的监控
Java生产环境性能监控与调优—基于JDK命令行工具的监控
Java生产环境性能监控与调优—基于JDK命令行工具的监控
|
XML 存储 监控
java日志(系统运行监控)
.什么是日志? 记录系统运行的过程和详情,并可以进行永久存储
198 0
java日志(系统运行监控)