cglib的最第一版本幹了什麼?

由於翻閱spring的源碼,看到overrides部分,牽扯到了cglib,加上後續立刻要進行的aop也要用到這個玩意兒,其實知道一些,說是用繼承的方法解決代理的問題。java

跟jdkproxy常常拿來比較,固然這兩個也是面試常常問的問題,固然仍是那句話,就木有一個技術難點經得起細看, 都是點只是沒看到的點而已,而後就會被人鄙視說這都不會,只想說,去你大爺的,老子只是沒看。git

好了廢話說多無益,來看下最初的版本吧,每每最初的版本是最核心的東西,以後的種種不過是錦上添花,那這錦纔是最須要研究的。github

github上cglib的版本最先的是面試

2002年的版本,咱們把代碼下載下來只有三個類。spring

把源碼拿到後,作了個例子看下,確實比較猛。apache

先看下代碼:ide

/*
 * Factory.java
 *
 */

package proxy.net.sf.cglib.proxy;

/**
 *
 * @author  user
 */
  public interface Factory{
      
       public Object newInstance(MethodInterceptor ih);
    }
   
    
public interface MethodInterceptor {
    
    /** Generated code calls this method first
     * @param obj this
     * @param method Intercepted method
     * @param args Arg array
     * @throws Throwable  any exeption to stop execution
     * @return returned value used as parameter for all
     * interceptor methods
     */    
  /*  public Object beforeInvoke( Object obj,
                                java.lang.reflect.Method method,
                                Object args[] )throws java.lang.Throwable;
   */
    
    /** Generated code calls this method before invoking super
     * @param obj this
     * @param method Method
     * @param args Arg array
     * @param retValFromBefore value returned from beforeInvoke
     * @throws Throwable any exeption to stop execution
     * @return true if need to invoke super
     */    
    public boolean invokeSuper(Object obj,
                               java.lang.reflect.Method method,
                               Object args[]
            /*,Object retValFromBefore*/)
                                             throws Throwable;
    
    /** this method is invoked after execution
     * @param obj this
     * @param method Method
     * @param args Arg array
     * @param retValFromBefore value returned from beforeInvoke
     * @param invokedSuper value returned from invoke super
     * @param retValFromSuper value returner from super
     * @param e Exception thrown by super
     * @throws Throwable any exeption
     * @return value to return from generated method
     */    
    public Object afterReturn(Object obj,
                              java.lang.reflect.Method method,
                              Object args[],
            /*Object retValFromBefore,*/
                              boolean invokedSuper,
                              Object retValFromSuper,
                              Throwable e)
                                             throws Throwable;
    
    
}

另外一個就是類:Enhance.java ,這個是核心類,內容比較多,這裏就不貼出來了。後邊咱們的分析裏,主要就是Enhance裏的代碼在作代碼加強。函數

下邊咱們來看下咱們寫的測試的例子:測試

定義一個接口優化

package cglib.test;

public interface Call {

    void call();
    void eat();
}

定義實例:

package cglib.test;

public class Dog implements Call{

    @Override
    public void call() {
        System.out.println("wang!wang!");
    }

    @Override
    public void eat() {
        System.out.println("eat!eat!");
    }
}

測試類:

package cglib.test;

import proxy.net.sf.cglib.proxy.Enhancer;
import proxy.net.sf.cglib.proxy.MethodInterceptor;

import java.lang.reflect.Method;

public class CglibTest {


    public static void main(String args[]){
try {
            Dog dog = (Dog)Enhancer.enhance(Dog.class, null, new MethodInterceptor() {
                @Override
                public boolean invokeSuper(Object obj, Method method, Object[] args) throws Throwable {

                    if(method.getName().equals("eat")){
                        System.out.println("before eat invoke ...");
                    }else if(method.getName().equals("call")){
                        System.out.println("before call invoke ...");
                    }
                    return true;
                }

                @Override
                public Object afterReturn(Object obj, Method method, Object[] args, boolean invokedSuper, Object retValFromSuper, Throwable e) throws Throwable {
                    System.out.println("after invoke ...");
                    return obj;
                }
            }, CglibTest.class.getClassLoader());

            dog.call();
            dog.eat();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

    }

}

測試結果:

before call invoke ...
wang!wang!
after invoke ...
before eat invoke ...
eat!eat!
after invoke ...

能夠看到已經根據咱們實現的MethodInteceptor進行了加強,輸出咱們想要的內容了。

嗯,代碼拿下來後,我是新建立的工程放入代碼的,發現有編譯錯誤,查看import的錯誤,是缺乏bcel jar包。去apache官網上下載一個相對比較老的5.2的版本。

沒錯就是這個包,查了下,就是用來生成加強類的。只不事後來cglib的這塊兒引用被asm替換掉了,固然asm應該是比bcel更強悍的。不過既然要看最初的版本,那咱們就仍是按照這個版原本看吧。那就避免不了要看bcel的東西了。

花點時間跟蹤下bcel的代碼咱們來看下最終生成的類:

生成的類名字:cglib.test.Dog$$EnhancedBySimplestore$$0

生成的類的call方法:

重點看下:21步/32步/53步

其實已經很明顯了,加強以後的類,call方法調用的時候,增長了咱們定義的那個MethodInteceptor的兩個方法,一個在call調用前調用,一個在call調用以後調用。

至於,其餘的方法咱們着重看下:構造函數

構造函數寫的比較明顯了,這裏要說明的是代碼加強裏,添加了屬性: public MethodInteceptor h;

構造函數裏,除了調用父類的構造函數外,就是把構造函數的參數裏的 MethodInteceptor賦值給這個h;

翻成代碼就是:

public Dog$$EnhancedBySimplestore$$0(MethodInteceptor h) {

  super();

  this.h = h;

}

而後,咱們來看添加的另外一個方法,另外一個方法就是接口Factory的實現方法:

也比較簡單,就是新建一個加強類的實例,而後調用它的<init>方法。而後把這個對象返回。其實就是建立加強累的實例。

翻譯過來就是:

public Dog newInstance(MethodInteceptor h){

  return new Dog$$EnhanceBySimplestore$$0(h).init();

}

可能翻譯的不太準確,但意思就是這個意思了。

至此咱們就把Enhance加強代碼作的事情,基本原理弄明白了。

寫的比較簡單,看了一下Enhance的代碼,但其實看了個大概已經花了一兩個鐘頭的時間了,期間作的代碼加強的事情,仍是挺強的。其實核心在於對於Class類結構的熟知以及對Bcel的使用。有了這兩樣東西,加上耐心,把cglib的事情作掉就並非難事了。

再來理解下cglib的這個最簡化版本的內容,咱們發現,其實咱們把Enhance這個具體的實現類去除後,就是兩個接口類。

那麼這兩個接口類就比較有意思了,一個是一個返回實例類的接口:

public Object newInstance(MethodInterceptor ih);

把MethodInteceptor實例做爲參數,構造出來一個對象。

一個是具體的MethodInteceptor接口自己,這個接口有兩個方法,一個是invokeSuper,一個是afterReturn。

思考一下,cglib的具體作的事情無外乎就是:

1:爲加強類添加一個MethodInteceptor的屬性h;

2:爲加強類添加一個以MethodInteceptor接口的實例爲參數的構造函數,並將MethodInteceptor的實例賦值給1步驟建立的屬性h。

3:爲加強類添加一個以MethodInteceptor接口的實例爲參數的newInstance方法,這個方法裏調用2步驟添加的構造函數,建立出加強累。

4:爲原始類的方法,增長加強實現。即在調用原始方法的先後,調用屬性h即傳入的MethodInteceptor的實例的那兩個invokeSuper和afterReturn方法。

思路,就是這麼簡單。把咱們的MethodInteceptor的實現,加強到原始類的方法中,就能夠了。藉助於代碼加強,和繼承的特性來實現了這個方案。

解析到這裏就結束了,相信cglib的後續版本作了不少的優化和其餘相關功能的添加。但最核心的這個事情應該是沒什麼大變更的,後續有時間再專門寫一篇來對比最新的版本作了那些事情。跟如今這個版本的核心代碼有什麼變更。

相關文章
相關標籤/搜索