如果想了解JDK动态代理可以看我这篇文章:彻底搞懂JDK动态代理
CGLIB(Code Generation Library)是一个强大的高性能的代码生成库,它扩展了Java的字节码操作框架ASM,提供了更加方便的API。CGLIB主要用于动态生成类和代理类,常用于实现AOP(面向切面编程)编程。
CGLIB代理具体实现
CGLIB是针对类实现代理,主要是对指定的类生成一个子类(继承
),覆盖其中的方法。
1.定义CGLIB代理的目标类
java
//目标类
public class TargetObject {
public void targetMethod() {
System.out.println("/// "+this.getClass().getName()+" 执行");
}
}
2.实现MethodInterceptor接口,重写intercept方法
MethodInterceptor
是一个接口,它定义了方法拦截器应该实现的方法。
java
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
方法获取代理对象
scss
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();
}

CGLIB代理原理

通过enhancer.create()
获取到代理接口的class(TargetObject$$EnhancerByCGLIB$$bdec66d0)
enhancer.create()
方法Debug后发现最后还是通过反射生成代理对象(TargetObject$$EnhancerByCGLIB$$bdec66d0
)
通过Arthas反编译TargetObject$$EnhancerByCGLIB$$bdec66d0
的源码,可以看到该类继承了目标接口 (ps:也可以通过下面的代码将生成类写入文件中)
Java
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./cglib");

从上面源码我们可以看到子类重写了父类的方法,调用了intercept()
方法,从而完成了由代理对象访问到目标对象的动态代理实现。
查看我们target
的文件夹,我们发现CGLIB除了生成代理对象类,还生成了两个FastClass类( FastClass f1,f2)(JDK动态代理只会生成一个代理类),代理类我们很容易理解,但这两个FastClass类用什么用呢?

FastClass调用机制
CGLIB采用FastClass机制,对代理类和目标类的方法建立签名hash映射,这样就可以直接调用,避免了反射调用目标类(JDK动态代理只能采用反射调用目标类)
CGLIB中我们使用methodProxy.invokeSuper()
方法调用目标方法,通过MethodProxy
的类的源码,发现其内部保存着对它们的引用

简单来说,多出来的这两个FastClass的作用是:
FastClass-f1:目标类(被代理对象)的映射,所有方法都转发到目标类
FastClass-f2:代理类的映射,所有方法都转发到代理类
在我们调用methodProxy.invokeSuper()
方法时,实际是直接利用 FastClass-f2 去调用的代理类,避免了反射调用。
总结
CGLIB代理目标可以不实现接口
CGLIB是针对类实现代理,生成一个之类,所以该类或方法最好不要声明成final, static方法,private方法,final方法是不能被代理的