java--字节码增强--1.3--ByteBuddy--ByteBuddy常用注解

java–字节码增强–1.3–ByteBuddy–ByteBuddy常用注解


1、介绍

Byte Buddy 还提供了一些预定义的注解,通过这些注解我们可以告诉 Byte Buddy 将哪些需要的数据注入到 Interceptor 中

2、常用注解

2.1、@RuntimeType

  1. 告诉 Byte Buddy 不要进行严格的参数类型检测,在参数匹配失败时,尝试使用类型转换方式(runtime type casting)进行类型转换,匹配相应方法。
  2. 可以用在返回值、参数上,提示ByteBuddy禁用严格的类型检查

public class Target { 

    @RuntimeType
    public static Object intercept(@RuntimeType Object value) {
        System.out.println("Invoked method with: " + value);
        return value;
    }

}

2.2、@This

注入被拦截的目标对象。

2.3、@AllArguments

注入目标方法的全部参数

2.4、@Origin

  1. 注入被拦截的源方法
  2. 如果拦截的是字段的话,该注解应该标注到 Field 类型参数。

2.5、@Super

  1. 注入当前被拦截的、动态生成的那个对象的父类对象
  2. 通过该对象可以调用目标对象的所有方法。

2.6、@SuperCall

  1. 这个注解比较特殊,我们要在 intercept() 方法中用于调用父类版本的方法,需要通过这种方式注入,
  2. @SuperCall与 Spring AOP 中的 ProceedingJoinPoint.proceed() 方法有点类似,需要注意的是,这里不能修改调用参数,
  3. @SuperCall 注解还可以修饰 Runnable 类型的参数,只不过目标方法的返回值就拿不到了。

2.7、@Argument

  1. 绑定单个参数
  2. 可以在拦截器(Target)的拦截方法,intercept 中使用注解注入参数,ByteBuddy 会根据注解给我们注入对于的参数值。比如
void intercept(Object o1, Object o2)
// 等同于
void intercept(@Argument(0) Object o1, @Argument(1) Object o2)

2.8、@DefaultCall

调用默认方法而非super的方法

2.9、@FieldValue

注入被拦截对象的一个字段的值

3、案例

3.1、代码结构

在这里插入图片描述

3.2、代码

LogInterceptor

package fei.zhou.demo1.business.ByteBuddy2.demo8;

import net.bytebuddy.implementation.bind.annotation.*;

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

public class LogInterceptor {

    @RuntimeType //将返回值转换成具体的方法返回值类型,加了这个注解 intercept 方法才会被执行
    public Object intercept(
            // 被拦截的目标对象 (动态生成的目标对象)
            @This Object target,
            // 正在执行的方法Method 对象(目标对象父类的Method)
            @Origin Method method,
            // 正在执行的方法的全部参数
            @AllArguments Object[] argumengts,
            // 目标对象的一个代理
            @Super Object delegate,
            // 方法的调用者对象 对原始方法的调用依靠它
            @SuperCall Callable<?> callable) throws Exception {
        //目标方法执行前执行日志记录
        System.out.println("执行目标方法 前:" + method.getName());
        // 调用目标方法
        Object result = callable.call();
        //目标方法执行后执行日志记录
        System.out.println("执行目标方法 后:" + method.getName());
        return result;
    }

}


UserService

package fei.zhou.demo1.business.ByteBuddy2.demo8;

public class UserService {

    //方法1
    public String method01() {
        System.out.println("我是方法1");
        return "method01";
    }

    //方法2
    public String method02(String str1) {
        System.out.println("我是方法2,参数1");
        return str1;
    }

    //方法3
    public String method02(String str1, String str2) {
        System.out.println("我是方法2,参数2");
        return str1 + str2;
    }
}

Test

package fei.zhou.demo1.business.ByteBuddy2.demo8;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;


public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Class<? extends UserService> aClass = new ByteBuddy()
                // 创建一个UserService 的子类
                .subclass(UserService.class)
                //指定类的名称
                .name("fei.zhou.UserServiceImpl")
                // 指定要拦截的方法
                //.method(ElementMatchers.isDeclaredBy(UserService.class))
                .method(ElementMatchers.named("method02").and(ElementMatchers.returns(String.class).and(ElementMatchers.takesArguments(1))))
                // 为方法添加拦截器 如果拦截器方法是静态的 这里可以传 LogInterceptor.class
                .intercept(MethodDelegation.to(new LogInterceptor()))
                // 动态创建对象,但还未加载
                .make()
                // 设置类加载器 并指定加载策略(默认WRAPPER)
                .load(ByteBuddy.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                // 开始加载得到 Class
                .getLoaded();
        UserService userService = aClass.newInstance();

        System.out.println("---------method01----------");
        System.out.println(userService.method01());

        System.out.println("---------method02 参数1----------");
        System.out.println(userService.method02("11111"));

        System.out.println("---------method02 参数2----------");
        System.out.println(userService.method02("2222", "3333"));
    }

}

3.3、结果

---------method01----------
我是方法1
method01
---------method02 参数1----------
执行目标方法 前:method02
我是方法2,参数1
执行目标方法 后:method02
11111
---------method02 参数2----------
我是方法2,参数2
22223333

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值