ByteBuddy基本用法

时间:2025-01-27 09:06:43

ByteBuddy是一种字节码技术框架,其广泛用于中间件开发,用于字节码增强,变更字节码的形式来拦截,用途如:链路追踪,系统JVM状态监控,耗时分析等。目前市面上常见的链路追踪框架为:skywalking、美团cat等。本博客有对应skywalking解析,链接为:/article/details/116092966

 

相关资料

官网:/

skywalking源码解析(不定期更新):/lidishan/kywalking-source-code-analysis

 

ByteBuddy参考代码

public class Boot {

    public static void main(String[] args) throws Exception {
        // 1 基本用法    /post/6844904151546069006
        base();

        // 2 耗时、入参出参    /post/6844904155102838792
        use();

        // 3 使用委托实现抽象类方法并注入自定义注解信息   /post/6844904159427166221
        abstractAnnonation();
    }

    private static void abstractAnnonation() {
        // -- 生成含有注解的泛型实现字类
        <?> dynamicType = new ByteBuddy()
                // 创建复杂类型的泛型注解
                .subclass((, ).build())
                // 添加类信息包括地址
                .name(().getName().concat(".").concat("UserRepository"))
                // 匹配处理的方法
                .method(("queryData"))
                // 交给委托函数
                .intercept(())
                // 拦截对应注解
                .annotateMethod(()
                        .define("methodName", "queryData")
                        .define("methodDesc", "查询数据").build())
                .annotateType(()
                        .define("alias", "dataApi")
                        .define("clazzDesc", "查询数据信息")
                        .define("timeOut", 350L).build())
                .make();
        // 输出类信息到目标文件夹下
        outputClazz((), 4);
    }

    private static void use() throws Exception {
        <?> dynamicType = new ByteBuddy()
                // 继承的类
                .subclass()
                // 被监控的方法
                .method(("queryUserInfo"))
                // 具体监控实现类
                .intercept(())
                .make();
        // 加载类
        Class<?> clazz = (())
                .getLoaded();
        // 调用方法,测试监控效果
        BizMethod bizMethod = new BizMethod();
        (("10001", "Adhl9dkl"));
        // !!!用反射调用才有效果,
        //      那premain怎么结合bytebuddy使用?通过(listener).installOn(inst)绑定
        ("queryUserInfo", , ).invoke((), "10001", "Adhl9dkl");
    }

    private static void base() throws Exception {
        // 1 第一次输出一个简单的结构体
        <?> dynamicType = new ByteBuddy()
                // 定义继承的类
                .subclass()
                // 定义命名空间
                .name("")
                .make();
        // 输出类字节码
        outputClazz((), 1);

        // 2 增加一些参数、属性信息
        <?> dynamicType2 = new ByteBuddy()
                // 定义继承的类
                .subclass()
                // 定义命名空间
                .name("")
                // 定义一个main方法,public权限,并且是static
                .defineMethod("main", ,  + )
                // 定义参数
                .withParameter(String[].class, "args")
                // 定义一个局部变量为"Hello World!"
                .intercept(("Hello World!"))
                .make();
        outputClazz((), 2);

        // 3 委托函数使用
        <?> dynamicType3 = new ByteBuddy()
                // 定义继承的类
                .subclass()
                // 定义命名空间
                .name("")
                // 定义一个main方法,public权限,并且是static
                .defineMethod("main", ,  + )
                // 定义参数
                .withParameter(String[].class, "args")
                // 定义委托的类,委托调用()方法
                .intercept(())
                .make();
        outputClazz((), 3);
        // 加载类
        Class<?> clazz = (()).getLoaded();
        // 反射调用
        ("main", String[].class).invoke((), (Object) new String[1]);
    }

    private static void outputClazz(byte[] bytes, Integer num) {
        FileOutputStream out = null;
        try {
            String pathName = ("/").getPath() + "ByteBuddyHelloWorld_" + num + ".class";
            out = new FileOutputStream(pathName);
            ("类输出路径:" + pathName);
            (bytes);
        } catch (Exception e) {
            ();
        } finally {
            if (null != out) {
                try {
                    ();
                } catch (IOException e) {
                    ();
                }
            }
        }
    }


}

上面会调用对应拦截器进行处理,下面举例一个拦截器

上面调用了intercept(()),会执行如下intercept()拦截方法

public class MonitorDemo {

    /**
     * 参考:/post/6844904155102838792
     * @RuntimeType 定义运行时的目标方法
     *
     * @SuperCall     用于调用父类版本的方法
     * @AllArguments  绑定所有参数的数组
     * @Argument     绑定单个参数. 0表示第一个参数
     * @This          当前被拦截的、动态生成的那个对象
     * @Super         当前被拦截的、动态生成的那个对象的父类对象
     * @Origin        具备多种用法,如下:
     *                - Method:被调用的原始方法
     *                - Constructor:被调用的原始构造器
     *                - Class:当前动态创建的类
     *                - MethodHandle MethodType String 动态类的toString()的返回值 int 动态方法的修饰符
     * @DefaultCall   调用默认方法而非super的方法
     * @Super         注入父类型对象,可以是接口,从而调用它的任何方法
     * @Empty         注入参数的类型的默认值
     * @StubValue     注入一个存根值。对于返回引用、void的方法,注入null;对于返回原始类型的方法,注入0
     * @FieldValue    注入被拦截对象的一个字段的值
     * @Morph         类似于@SuperCall,但是允许指定调用参数
     */
    @RuntimeType
    public static Object intercept(@SuperCall Callable<?> callable,
                                   @AllArguments Object[] args,
                                   @Argument(0) Object uid,
                                   @This Object thisObj,
                                   @Super Object parentObj,
                                   @Origin Method method)
            throws Exception {
        long start = ();
        Object resObj = null;
        try {
            // @SuperCall 调用原方法
            resObj = ();
            return resObj;
        } finally {
            ("===============MonitorDemo======================");
            ("@AllArguments获取所有参数:" + (args));
            ("@Argument(0)获取第一个参数结果:" + uid);
            ("@This当前对象spanId结果:" + ((BizMethod) thisObj).getSpanId());
            ("@Super父类对象结果:" + ());
            ("@Origin方法名称:" + ());
            ("@Origin入参个数:" + ());
            ("@Origin入参类型:" + ()[0].getTypeName() + "、" + ()[1].getTypeName());
            ("@Origin出参类型:" + ().getName());
            ("方法耗时:" + (() - start) + "ms");
            ("===============MonitorDemo======================");
        }
    }

 

 

 

 

相关文章