詳解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和網上優秀博文總結,不當之處,望你們指出,學習 !學習!

相關文章
相關標籤/搜索