字节码JavaAgent ByteBuddy操作监控方法 字节码

Posted 九师兄

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字节码JavaAgent ByteBuddy操作监控方法 字节码相关的知识,希望对你有一定的参考价值。

1.概述

上一篇文章:【字节码】javaagent 入门 案例 最简单的案例

转载:https://github.com/fuzhengwei/itstack-demo-bytecode

在第二章中我们已经可以监控方法执行耗时,虽然它能完成我们一些基本需要,但是为了增强代码的扩展性,我们需要使用字节码操作工具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.


MethodCostTime


import net.bytebuddy.asm.Advice;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

public class MethodCostTime 

    @RuntimeType
    public static Object intercept(@Advice.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");
        
    


MyPreMainAgent

package com.javaagent.bytebuddy;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;

import java.lang.instrument.Instrumentation;

public class MyPreMainAgent 

    //JVM 首先尝试在代理类上调用以下方法
    public static void premain(String agentArgs, Instrumentation inst)
        System.out.println("this is my agent:" + agentArgs);

        AgentBuilder.Transformer transformer = ((builder, typeDescription, classLoader, javaModule) -> 
            DynamicType.Builder.MethodDefinition.ReceiverTypeDefinition<?> receiverTypeDefinition
                    = builder.method(ElementMatchers.any())// 拦截任意方法
                    .intercept(MethodDelegation.to(MethodCostTime.class)); // 委托
            return receiverTypeDefinition;
        );

        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.bytebuddy.service.demo4")) // 指定需要拦截的类
                .transform(transformer)
                .with(listener)
                .installOn(inst);
    

    //如果代理类没有实现上面的方法,那么 JVM 将尝试调用该方法
    public static void premain(String agentArgs) 
    



MethodCostAgentTest


public class MethodCostAgentTest 


    public static void main(String[] args) throws InterruptedException 
        MethodCostAgentTest apiTest = new MethodCostAgentTest();
        apiTest.echoHi();
    

    private void echoHi() throws InterruptedException 
        System.out.println("hi agent");
        Thread.sleep((long) (Math.random() * 500));
    

maven设置如下


    <properties>
        <asm.version>9.0</asm.version>
        <slf4j-api.version>1.7.28</slf4j-api.version>
        <byte-buddy.version>1.12.11</byte-buddy.version>
        <fastjson.version>1.2.76</fastjson.version>
        <lombok.version>1.18.16</lombok.version>
    </properties>

    <dependencies>

        <!-- 日志 相关 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>$slf4j-api.version</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>$slf4j-api.version</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>$fastjson.version</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>$lombok.version</version>
        </dependency>

        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy</artifactId>
            <version>$byte-buddy.version</version>
        </dependency>
        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy-agent</artifactId>
            <version>$byte-buddy.version</version>
        </dependency>

        <dependency>
            <groupId>com.bytebuddy</groupId>
            <artifactId>byte-buddy-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>


    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <addClasspath>true</addClasspath>
                            <Premain-Class>com.javaagent.bytebuddy.MyPreMainAgent</Premain-Class>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                            <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

打包如下

byte-buddy-v1x-javaagent-demo3]$ mvn clean package -DskipTests

设置参数 -javaagent:/Users/lcc/IdeaProjects/lcc_work/test-byte-buddy/byte-buddy-v1x-javaagent-demo3/target/byte-buddy-v1x-javaagent-demo3-1.0-SNAPSHOT.jar=testargs


运行结果如下

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
 
   

以上是关于字节码JavaAgent ByteBuddy操作监控方法 字节码的主要内容,如果未能解决你的问题,请参考以下文章

字节码Byte-buddy 监控方法执行耗时动态获取出入参类型 和值

字节码JavaAgent的全链路监控篇二,通过字节码增加监控执行 耗时

字节码javaagent 入门 案例 最简单的案例

字节码基于JavaAgent的全链路监控六 开发应用级监控

字节码基于JavaAgent的全链路监控六 基于jvmti定位java异常信 息

字节码基于JavaAgent的全链路监控五- ThreadLocal链路追踪