由於翻閱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的後續版本作了不少的優化和其餘相關功能的添加。但最核心的這個事情應該是沒什麼大變更的,後續有時間再專門寫一篇來對比最新的版本作了那些事情。跟如今這個版本的核心代碼有什麼變更。