Java动态代理Cglib代理

JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。

为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB 通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理。

在 CGLIB 动态代理机制中 MethodInterceptor 接口和 Enhancer 类是核心。

你需要自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法。

public interface MethodInterceptor
extends Callback{
    // 拦截被代理类中的方法
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                               MethodProxy proxy) throws Throwable;
}
Copy to clipboardErrorCopied
  1. obj :被代理的对象(需要增强的对象)

  2. method :被拦截的方法(需要增强的方法)

  3. args :方法入参

  4. methodProxy :用于调用原始方法

你可以通过 Enhancer类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor 中的 intercept 方法。

CGLIB 动态代理类使用步骤

  1. 定义一个类;

  2. 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中的 invoke 方法类似;

  3. 通过 Enhancer 类的 create()创建代理类;

依赖

<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>3.3.0</version>
</dependency>
​

代码示例 

1、定义类


/**
 * @author lin
 * @version 1.0
 * @date 2021/3/27 17:59
 * @Description 1、定义一个类
 */
public class AliSmsService {
    public String send(String message) {
        System.out.println("send message:" + message);
        return message;
    }
}

2、自定义MethodInterceptor

/**
 * @author lin
 * @version 1.0
 * @date 2021/3/27 18:01
 * @Description 2、实现 MethodInterceptor
 */
public class DebugMethodInterceptor implements MethodInterceptor {


    /**
     * @param obj    被代理的对象(需要增强的对象)
     * @param method 被拦截的方法(需要增强的方法)
     * @param args   方法入参
     * @param proxy  用于调用原始方法
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        if (method.getDeclaringClass().equals(Object.class)) {
            return method.invoke(this, args);
        }
        //调用方法之前,我们可以添加自己的操作
        System.out.println("before method " + method.getName());
        Object object = null;
        if (method.getDeclaringClass().isInterface()) {
            if (method.getName().equals("hello")) {
                object = "hello";
            }
        } else {
            object = proxy.invokeSuper(obj, args);
        }

        //调用方法之后,我们同样可以添加自己的操作
        System.out.println("after method " + method.getName());
        return object;
    }
}

3、通过 Enhancer 创建代理类

/**
 * @author lin
 * @version 1.0
 * @date 2021/3/27 18:06
 * @Description 3、通过 Enhancer 类的 create()创建代理类;
 */
public class CglibProxyFactory {

    public static <T> T getObject(Class<T> clazz) {
        //1、创建 Enhancer 动态代理增加类
        Enhancer enhancer = new Enhancer();
        //2、设置 类加载器
        enhancer.setClassLoader(clazz.getClassLoader());
        //3、设置 被代理对象
        enhancer.setSuperclass(clazz);
        //4、设置 代理对象 ==> 设置方法拦截器
        enhancer.setCallback(new DebugMethodInterceptor());
        //5、创建 增加对象
        return (T) enhancer.create();
    }
}

测试

    @Test
    public void test01() {
        // 实际使用
        AliSmsService aliSmsService = CglibProxyFactory.getObject(AliSmsService.class);
        aliSmsService.send(" 恭喜你中奖了,本次放松的获奖验证码为: 88888 ");
    }

    //测试 代理接口

    @Test
    public void test02() {
        // 实际使用
        UserMapper userMapper = CglibProxyFactory.getObject(UserMapper.class);
        System.out.println(userMapper.hello());
    }

    //接口
    /**
     * TODO
     *
     * @author 发哥讲Java
     * @version 1.0    
     * @date 2021-03-10 16:27
     */
    public interface UserMapper {
        public String hello();
        public String hello2();
    
    }    

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

航迹者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值