CGLIB原理
cglib是一个java字节码的生成工具,它动态生成一个被代理类的子类,子类重写被代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
示例
被代理类:
public class HelloServiceImpl {
public void sayHello(){
System.out.println("Hello Zhanghao");
}
public void sayBey(){
System.out.println("Bye Zhanghao");
}
}
实现MethodInterceptor接口生成方法拦截器:
public class HelloMethodInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Before: " + method.getName());
Object object = methodProxy.invokeSuper(o, objects);
System.out.println("After: " + method.getName());
return object;
}
}
生成代理类对象并打印在代理类对象调用方法之后的执行结果:
public class Client {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/zhanghao/Documents/toy/spring-framework-source-study/");
Enhancer enhancer = new Enhancer();
//继承被代理类
enhancer.setSuperclass(HelloServiceImpl.class);
//设置回调
enhancer.setCallback(new HelloMethodInterceptor());
//设置代理类对象
HelloServiceImpl helloService = (HelloServiceImpl) enhancer.create();
//在调用代理类中方法时会被我们实现的方法拦截器进行拦截
helloService.sayBey();
}
}
result:
Before: sayBey
Bye Zhanghao
After: sayBey
构建代理类过程
我们可以从上面的代码示例中看到,代理类是由enhancer.create()创建的。Enhancer是CGLIB的字节码增强器,可以很方便的对类进行拓展。
创建代理类的过程:
- 生成代理类的二进制字节码文件;
- 加载二进制字节码,生成Class对象;
- 通过反射机制获得实例构造,并创建代理类对象。
enhancer.create()实现:
/**
* Generate a new class if necessary and uses the specified
* callbacks (if any) to create a new object instance.
* Uses the no-arg constructor of the superclass.
* @return a new instance
*/
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}
private Object createHelper() {
validate();
if (superclass != null) {
//设置生成类的名称
setNamePrefix(superclass.getName());
} else if (interfaces != null) {
//设置生成类的名称
setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName());
}
//生成代理类对象(在KEY_FACTORY.newInstance(...)->生成代理类的二进制字节码文件以及加载二进制字节码)
return super.create(KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter,
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID));
}
cglic一共会自动生成三个字节码文件。其中一个类HelloServiceImpld855d4dc 继承了被代理类 HelloServiceImpl。这个类就是加强的代理类,其中会生成两个方法CGLIB
1()和sayHello()。
其中sayHello():
public final void sayHello() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if(this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if(var10000 != null) {
var10000.intercept(this, CGLIB$sayHello$1$Method, CGLIB$emptyArgs, CGLIB$sayHello$1$Proxy);
} else {
super.sayHello();
}
}
当代理对象的执行sayHello方法时,会首先判断一下是否存在实现了MethodInterceptor接口的CGLIB$CALLBACK_0;,如果存在,则将调用MethodInterceptor中的intercept方法。
与JDK代理对比
JDK代理要求被代理的类必须实现接口,有很强的局限性。而CGLIB动态代理则没有此类强制性要求。简单的说,CGLIB会让生成的代理类继承被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等)。但是如果被代理类被final修饰,那么它不可被继承,即不可被代理;同样,如果被代理类中存在final修饰的方法,那么该方法也不可被代理。