详解Java动态代理机制(二)----cglib实现动态代理

     上篇文章的结尾咱们介绍了普通的jdk实现动态代理的主要不足在于:它只能代理实现了接口的类,若是一个类没有继承于任何的接口,那么就不能代理该类,缘由是咱们动态生成的全部代理类都必须继承Proxy这个类,正是由于Java的单继承,因此注定会抛弃原类型的父类。而咱们的cglib经过扫描该类以及其父类中全部的public非final修饰的方法,经过asm定义该类的子类字节码,其中该子类重写了父类全部的方法,而后返回该子类的实例做为代理类。也就是说咱们的cglib是用该类的子类做为代理类来实现代理操做的。固然cglib的缺点也是呼之欲出,对于被代理类中的非public或者final修饰的方法,不能实现代理。java

     在详细介绍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建立的代理类是原对象的子类型,因此这里称原类型实例为父类也是合理的。ui

跟进去,咱们看到:this

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的时候提供帮助。code

接下来是setCallback方法,该方法设置了回调。也就是未来对咱们代理中方法的访问会转发到该回调中,全部自定义的回调类必须继承MethodInterceptor接口并实现其intercept方法,这一点和jdk的InvocationHandler相似。这里的intercept有几个参数:对象

  • Object obj:被代理的原对象
  • Method method:被调用的当前方法
  • Object[] args:该方法的参数集合
  • MethodProxy proxy:被调用方法的代理,它能够和method完成一样的事情,可是它使用FastClass机制非反射执行方法,效率高

咱们对于全部调用代理方法的请求,转发到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和网上优秀博文总结,不当之处,望你们指出,学习 !学习!

相关文章
相关标签/搜索