彻底搞懂CGLIB代理

本文详细介绍了CGLIB库如何通过代码生成实现类级别的动态代理,包括目标类的定义、MethodInterceptor接口的应用以及Enhancer类的使用。重点讲解了CGLIB的FastClass机制,它如何加速代理过程并避免反射调用。
摘要由CSDN通过智能技术生成

如果想了解JDK动态代理可以看我这篇文章:彻底搞懂JDK动态代理

CGLIB(Code Generation Library)是一个强大的高性能的代码生成库,它扩展了Java的字节码操作框架ASM,提供了更加方便的API。CGLIB主要用于动态生成类和代理类,常用于实现AOP(面向切面编程)编程。

CGLIB代理具体实现

CGLIB是针对类实现代理,主要是对指定的类生成一个子类(继承),覆盖其中的方法。

1.定义CGLIB代理的目标类

//目标类
public class TargetObject {

    public void targetMethod() {
        System.out.println("/// "+this.getClass().getName()+" 执行");
    }
}

2.实现MethodInterceptor接口,重写intercept方法

MethodInterceptor 是一个接口,它定义了方法拦截器应该实现的方法。

public class AopCglibInvocation implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println("/// "+this.getClass().getName()+" 执行前");

        methodProxy.invokeSuper(o, objects);

        System.out.println("/// "+this.getClass().getName()+" 执行后");

        return null;
    }
}

MethodInterceptor接口只有一个方法,即intercept()方法,它负责处理对代理对象的方法调用。

对比JDK动态代理实现的InvocationHandler接口,看到都实现了对应的接口,重写了里面的方法。
区别在于:不再需要代理类的引用对象了 因为intercept()方法中,含有了methodProxy参数,可以直接直接通过proxy 对象访问被代理对象的方法,如果使用method.invoke(将目标对象作为拦截器的成员变量,但是不建议),会出现栈溢出等问题,后面的内容我们会说到为什么不建议

3.通过Enhancer类创建动态代理对象

Enhancer类是CGLIB中的一个类,既能够代理普通的class,也能够代理接口(JDK中的Proxy只能代理接口)

Enhancer类主要用到的方法:

  • enhancer.setSuperclass用来设置代理类的父类,即需要给哪个类创建代理类

  • enhancer.setCallback传递的是MethodInterceptor接口类型的参数,这个MethodInterceptor接口的intercept方法会拦截代理对象所有的方法调用。

  • enhancer.setCallbacks顾名思义 传递的是MethodInterceptor接口类型的参数数组

  • enhancer.setCallbackFilter设置回调选择器,我们通过CallbackFilter可以实现不同的方法使用不同的回调方法

  • enhancer.create方法获取代理对象

public static void main(String[] args) {
    // 创建AopCglibInvocation对象
    AopCglibInvocation aopCglibInvocation = new AopCglibInvocation();

    // 创建Enhancer对象
    Enhancer enhancer = new Enhancer();
    // 设置代理对象的超类为TargetObject类
    enhancer.setSuperclass(TargetObject.class);
    // 设置回调对象为AopCglibInvocation对象
    enhancer.setCallback(aopCglibInvocation);

    // 创建代理对象
    TargetObject proxy = (TargetObject) enhancer.create();
    // 调用代理对象的targetMethod方法
    proxy.targetMethod();
}

image.png

CGLIB代理原理

image.png

通过enhancer.create() 获取到代理接口的class(TargetObject$$EnhancerByCGLIB$$bdec66d0)
image.png

enhancer.create()方法Debug后发现最后还是通过反射生成代理对象(TargetObject$$EnhancerByCGLIB$$bdec66d0
image.png

通过Arthas反编译TargetObject$$EnhancerByCGLIB$$bdec66d0的源码,可以看到该类继承了目标接口
(ps:也可以通过下面的代码将生成类写入文件中)

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./cglib");

image.png

从上面源码我们可以看到子类重写了父类的方法,调用了intercept()方法,从而完成了由代理对象访问到目标对象的动态代理实现。

查看我们target的文件夹,我们发现CGLIB除了生成代理对象类,还生成了两个FastClass类(
FastClass f1,f2)(JDK动态代理只会生成一个代理类),代理类我们很容易理解,但这两个FastClass类用什么用呢?

image.png

FastClass调用机制

CGLIB采用FastClass机制,对代理类和目标类的方法建立签名hash映射,这样就可以直接调用,避免了反射调用目标类(JDK动态代理只能采用反射调用目标类)

CGLIB中我们使用methodProxy.invokeSuper()方法调用目标方法,通过MethodProxy的类的源码,发现其内部保存着对它们的引用

image.png

简单来说,多出来的这两个FastClass的作用是:

FastClass-f1:目标类(被代理对象)的映射,所有方法都转发到目标类

FastClass-f2:代理类的映射,所有方法都转发到代理类

在我们调用methodProxy.invokeSuper()方法时,实际是直接利用
FastClass-f2 去调用的代理类,避免了反射调用。

总结

CGLIB代理目标可以不实现接口

CGLIB是针对类实现代理,生成一个之类,所以该类或方法最好不要声明成final, static方法,private方法,final方法是不能被代理的

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值