上篇文章的结尾我们介绍了普通的 jdk 实现动态代理的主要不足在于:它只能代理实现了接口的类,如果一个类没有继承于任何的接口,那么就不能代理该类,原因是我们动态生成的所有代理类都必须继承 Proxy 这个类,正是因为 Java 的单继承,所以注定会抛弃原类型的父类。而我们的 cglib 通过扫描该类以及其父类中所有的 public 非 final 修饰的方法,通过 asm 定义该类的子类字节码,其中该子类重写了父类所有的方法,然后返回该子类的实例作为代理类。也就是说我们的 cglib 是用该类的子类作为代理类来实现代理操作的。当然 cglib 的缺点也是呼之欲出,对于被代理类中的非 public 或者 final 修饰的方法,不能实现代理。
在详细介绍 cglib 之前,我们先简单介绍下 ASM 框架,这是一个小而快的字节码处理框架,它负责生成从被代理类中扫描出的方法的字节码并将这些方法生成字节码暂存在内存中。然后我们通过方法将这些字节码转换成 class 类型,最后利用反射创建代理类的实例返回。下面看一个完整的实例,稍后从源代码的角度分析这个实例:
- //定义一个接口
- public interface MyInterface {
- public void sayHello();
- }
- //定义一个ClassB类
- public class ClassB {
- public void welcome(){
- System.out.println("welcom walker");
- }
- }
- //模拟被代理的类,继承了ClassB和接口MyInterface
- public class ClassA extends ClassB implements MyInterface {
- public void sayHello(){
- System.out.println("hello walker");
- }
- }
- //定义一个回调实例,稍后解释
- public class MyMethod implements MethodInterceptor {
- public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
- MethodProxy proxy) throws Throwable{
- proxy.invokeSuper(obj, args);
- return null;
- }
- }
- public class Test {
- public static void main(String[] args) throws Exception {
- ClassA ca = new ClassA();
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(ClassA.class);
- enhancer.setCallback(new MyMethod());
- ClassA my = (ClassA)enhancer.create();
- my.welcome();
- }
- }
- 输出结果:welcom walker
我们看到,此处我们获取了 ClassA 的代理对象,然后调用了 ClassA 父类中的 welcome 方法。这也间接证明了我们通过 cglib 代理了 ClassA 的父类中的方法,这一点使用 jdk 实现的动态处理是做不到的。下面我们解释原理。
在这之前,由于 cglib 是第三方库,所以我们需要下载相应的 jar 文件,主要包含两个文件,一个是 cglib 的 jar,还有一个是 cglib 依赖的 ASM 框架的 jar 文件,注意这两个 jar 的版本不能冲突。
我们从 main 方法的主体代码中可以看出,Enhancer 类是创建代理实例的核心类。没错,该类负责整个代理对象的生命周期,它就像是一个工具一样,提供了很多方法帮助我们创建代理实例。首先我们调用了 setSuperclass 方法设置父类型,其实也就是将被代理对象传入,因为我们之前说过 cglib 创建的代理类是原对象的子类型,所以这里称原类型实例为父类也是合理的。
跟进去,我们看到:
- public void setSuperclass(Class superclass) {
- if ((superclass != null) && (superclass.isInterface())) {
- setInterfaces(new Class[] {
- superclass
- });
- } else if ((superclass != null) && (superclass.equals(Object.class))) {
- this.superclass = null;
- } else {
- this.superclass = superclass;
- }
- }
这段代码的主要意思是:如果传入的类型是接口的话,保存在专门用于保存接口类型的变量中。
- private Class[] interfaces;
如果传入的类型是 Object 类型的话,将用于保存普通类类型的变量赋值为 null,否则保存该传入的参数的值在该变量中。这些操作过程中保存的一些数值是为了在最后 create 的时候提供帮助。
接下来是 setCallback 方法,该方法设置了回调。也就是将来对我们代理中方法的访问会转发到该回调中,所有自定义的回调类必须继承 MethodInterceptor 接口并实现其 intercept 方法,这一点和 jdk 的 InvocationHandler 类似。这里的 intercept 有几个参数:
我们对于所有调用代理方法的请求,转发到 invokeSuper 方法中,该方法源码如下:
- //fastclassinfo类
- private static class FastClassInfo
- {
- FastClass f1;
- FastClass f2;
- int i1;
- int i2;
- private FastClassInfo() {}
- FastClassInfo(MethodProxy.1 x0)
- {
- this();
- }
- }
- public Object invokeSuper(Object obj, Object[] args)
- throws Throwable
- {
- try
- {
- init();
- FastClassInfo fci = this.fastClassInfo;
- return fci.f2.invoke(fci.i2, obj, args);
- }
- catch (InvocationTargetException e)
- {
- throw e.getTargetException();
- }
- }
其中 fastclassinfo 类中,几个参数的意思解释下,f1 指向被代理对象,f2 指向代理类对象,i1 和 i2 分别是代理类中的该方法的两个索引。也就是这种 fastclass 机制并不是通过反射找到指定的方法的,而是在创建代理类的时候为其中的方法建立 hash 索引,这样调用的时候通过索引调用提高了效率。最后调用了代理类的方法,也就是重写了父类的方法。
最后也是最核心的一步是 create 方法的调用,这个方法才是实际创建代理实例的方法,我们看源码:
- public Object create()
- {
- this.classOnly = false;
- this.argumentTypes = null;
- return createHelper();
- }
该方法主要设置了两个参数配置,指定将要创建的对象不仅仅是一个类,指定参数为空。至于这两个参数有何作用,还需要往下追,我们看 createHelper 类:
- private Object createHelper()
- {
- validate();
- if (this.superclass != null) {
- setNamePrefix(this.superclass.getName());
- } else if (this.interfaces != null) {
- setNamePrefix(this.interfaces[ReflectUtils.findPackageProtected(this.interfaces)].getName());
- }
- return super.create(KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter, this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID));
- }
validate() 方法主要对于一些参数进行校验,如果不符合创建实例的标准将抛出异常,我们可以简单的看一眼:
- private void validate()
- {
- if ((this.classOnly ^ this.callbacks == null))
- {
- if (this.classOnly) {
- throw new IllegalStateException("createClass does not accept callbacks");
- }
- throw new IllegalStateException("Callbacks are required");
- }
- if ((this.classOnly) && (this.callbackTypes == null)) {
- throw new IllegalStateException("Callback types are required");
- }
- if ((this.callbacks != null) && (this.callbackTypes != null))
- {
- if (this.callbacks.length != this.callbackTypes.length) {
- throw new IllegalStateException("Lengths of callback and callback types array must be the same");
- ..........
- ..........
- .........
- }
主要还是判断回调是否指定,类型是否正确等,如果不符合创建条件就抛出异常。我们回去,接着就做了两个判断,用于指定被创建的代理类的名称,我们暂时不管他。又到了一个核心的方法,该方法将创建代理类并返回该类实例。首先我们看参数都是是什么意思,就一个参数,该参数是由 KEY_FACTORY.newInstance 方法返回的一个 Object 类型,我们看到在该方法的传入参数中,包括了父类类名或者接口名,回调类型,版本号等。该方法实际上返回了一个该代理类的一个唯一标识,这还不是关键,最关键的方法是这个 create 方法:
- protected Object create(Object key)
- {
- try
- {
- Class gen = null;
- synchronized (this.source)
- {
- ClassLoader loader = getClassLoader();
- Map cache2 = null;
- cache2 = (Map)this.source.cache.get(loader);
- if (cache2 == null)
- {
- cache2 = new HashMap();
- cache2.put(NAME_KEY, new HashSet());
- this.source.cache.put(loader, cache2);
- }
- else if (this.useCache)
- {
- Reference ref = (Reference)cache2.get(key);
- gen = (Class)(ref == null ? null : ref.get());
- }
- if (gen == null)
- {
- Object save = CURRENT.get();
- CURRENT.set(this);
- try
- {
- this.key = key;
- if (this.attemptLoad) {
- try
- {
- gen = loader.loadClass(getClassName());
- }
- catch (ClassNotFoundException e) {}
- }
- if (gen == null)
- {
- b = this.strategy.generate(this);
- String className = ClassNameReader.getClassName(new ClassReader(b));
- getClassNameCache(loader).add(className);
- gen = ReflectUtils.defineClass(className, b, loader);
- }
- if (this.useCache) {
- cache2.put(key, new WeakReference(gen));
- }
- byte[] b = firstInstance(gen);
- CURRENT.set(save);return b;
- }
- finally
- {
- CURRENT.set(save);
- }
- }
- }
- return firstInstance(gen);
- //省去了异常捕获的代码块
如果 usecache 为为 true 表明该代理类已经在 cache 中了,直接返回引用即可。否则通过 this.strategy.generate(this); 方法生成该代理类的字节码,然后通过通过类加载器加载该字节码生成 class 类型,最后通过 firstInstance 方法生成代理类的实例返回。
最后我们看一眼刚才生成的代理的源码:
- //代码很多,此处贴出部分
- public class ClassA$$EnhancerByCGLIB$$64984e8e extends ClassA
- implements Factory
- {
- final void CGLIB$sayHello$0()
- {
- super.sayHello();
- }
- public final void sayHello()
- {
- CGLIB$CALLBACK_0;
- if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
- _L1:
- JVM INSTR pop ;
- CGLIB$BIND_CALLBACKS(this);
- CGLIB$CALLBACK_0;
- _L2:
- JVM INSTR dup ;
- JVM INSTR ifnull 37;
- goto _L3 _L4
- _L3:
- break MISSING_BLOCK_LABEL_21;
- _L4:
- break MISSING_BLOCK_LABEL_37;
- this;
- CGLIB$sayHello$0$Method;
- CGLIB$emptyArgs;
- CGLIB$sayHello$0$Proxy;
- intercept();
- return;
- super.sayHello();
- return;
- }
- final void CGLIB$welcome$1()
- {
- super.welcome();
- }
- public final void welcome()
- {
- CGLIB$CALLBACK_0;
- if(CGLIB$CALLBACK_0 != null) goto _L2; else goto _L1
- _L1:
- JVM INSTR pop ;
- CGLIB$BIND_CALLBACKS(this);
- CGLIB$CALLBACK_0;
- _L2:
- JVM INSTR dup ;
- JVM INSTR ifnull 37;
- goto _L3 _L4
- _L3:
- break MISSING_BLOCK_LABEL_21;
- _L4:
- break MISSING_BLOCK_LABEL_37;
- this;
- CGLIB$welcome$1$Method;
- CGLIB$emptyArgs;
- CGLIB$welcome$1$Proxy;
- intercept();
- return;
- super.welcome();
- return;
- }
- ....
- ....
- }
从中我们看到,该类 ClassA$$EnhancerByCGLIB$$64984e8e 继承自 ClassA,实现了接口 factory。并且在其中我们看到不仅是父类 ClassA 中的方法 sayHello 在其中被重写了之外,ClassA 的父类 ClassB 中的 welcome 方法也被重写了。足以见得,cglib 利用继承的方式动态创建了被代理类的子类,通过 ASM 生成父类中所有 public 非 final 修饰的方法,实现了代理。
最后稍微小结下,cglib 的实现代理的逻辑。首先我们通过 Enhancer 实例设置被代理类,然后设置该代理类的回调,也就是在访问代理类方法的时候会首先转向该回调,在回调中我们调用 invokeSuper 方法以 fastclass 这种非反射机制快速的调用到代理类中的方法,其中代理类中方法又调用原类型的对应方法。
由于 cglib 已经停止维护好多年,导致参考文档很少,学习难度很大,此篇文章也是作者研读 jdk 和网上优秀博文总结,不当之处,望大家指出,学习 !学习!
来源: http://www.cnblogs.com/yangming1996/p/6824249.html