cglib是一种动态代理方式,底层通过asm产生class字节码来完成动态代理,cglib与jdk动态代理相比,除了可以代理实现接口的类也可以代理非实现接口的类,通过fastclass类来避免了java反射的使用。对jdk7以前的版本来说,jdk动态代理执行效率明显要比cglib动态代理类效率差,jdk8即以后版本对jdk动态代理进行了相应的优化,这种差距就不那么明显了。但是要代理不实现接口的类来说,cglib就是一种必要选择。
cglib代理一个类时会产生3个class文件,
上面标红部分的类就是两个相关类对应的fastclass文件,HelloServiceImpl
bc82cc02.class这个文件是被代理类对应的fastclass文件,HelloServiceImpl
75d5f5ba
15a4adc1.class是产生的代理类对应的fastclass文件,下面看我们经常使用的代码:
Enhancer enh = new Enhancer();
enh.setSuperclass(HelloServiceImpl.class);
HelloMethodInterceptor inteceptor = new HelloMethodInterceptor();
HelloServiceImpl hello = new HelloServiceImpl();
inteceptor.setTarget(hello);
enh.setCallbacks(new Callback[]{inteceptor});
HelloServiceImpl serv = (HelloServiceImpl)enh.create();
serv.sayHello();
上面标红部分代码产生的实例就是HelloServiceImpl
75d5f5ba.class这个类对象的实例,下面看下这个类相关部分代码:
public final void sayHello() { MethodInterceptor var10000 = this.CGLIBCALLBACK_0; if (this.CGLIBCALLBACK_0 == null) { CGLIBBIND_CALLBACKS(this); var10000 = this.CGLIBCALLBACK_0; }
if (var10000 != null) { var10000.intercept(this, CGLIBsayHello0Method, CGLIBemptyArgs, CGLIBsayHello0
上面的CALLBACK_0对应的就是HelloMethodInterceptor这个类,所以serv.sayHello()会转而调用HelloMethodInterceptor的intercept方法,下面看下HelloMethodInterceptor这个类:
public class HelloMethodInterceptor implements MethodInterceptor {
private Object target;
public HelloMethodInterceptor(Object target){
this.target = target;
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
System.out.println("before"+arg1.getName());
Object res = arg3.invokeSuper(arg0, arg2); //可以
//Object res = arg1.invoke(target, arg2); //可以
System.out.println("after"+arg1.getName());
return res;
}
}
至于HelloMethodInterceptor类的intercept方法里面每个入参代表什么值可以参考产生的代理类sayHello方法,这里就不再赘述。
注:
上面标紫色部分的代码不推荐使用,因为这样就会使用到反射,而且这种方法调用需要确保HelloMethodInterceptor类的target为被代理类而不能为创建的代理类,如果target为创建的代理类就会导致无限循环直到抛出StackOverflow异常。
至于为什么会导致循环调用呢,原因就在于:
arg1对应的是sayHello方法,但是反射调用传入的target却为代理类,根据java的多态性最终调用的还是代理类的sayHello方法。