Jdk的動態代理是在方法調用期間來動態生成代理的字節碼類,而後進行方法調用,好比自己方法是save()方法,而後實際調用save方法的時候不會直接調用save方法,而是先去調用一個代理方法save,而後經過代理方法去調用代理監控類的invoke方法,而後咱們就能夠在invoke方法中再去調用實際的save方法,而且能夠定製個性化的需求.緩存
jdk提供瞭如何實現動態代理的方法,有幾個要求,app
1.創建一個代理的監控類這個類必須實現InvocationHandler接口,重寫他的invoke方法,在invoke方法中進行個性化定製和實際方法的調用函數
2.要想被代理,那被代理對象必須實現接口,jdk動態代理是基於接口來代理的,因此實現類中本身特點的方法是沒辦法使用jdk動態代理加強的工具
3.jdk提供了一個工具類來生成代理對象Proxy,提供了一個靜態方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)來幫忙快速建立代理類,代理
參數1:被代理類加載的時候用的類加載器(用來加載動態建立的代理類的字節碼)對象
參數2:被代理類實現的全部接口,要給動態建立的代理類的字節碼實現這些接口,而且做爲標識能夠判斷是否已經緩存過實現這些接口的代理類避免重複建立接口
參數3:自定義的代理的監控類,會做爲構造函數的參數,賦值給新建立的代理類字節碼生成對象的成員變量InvocationHandler h;v8
大體理解下邏輯,Proxy類調用newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)get
1.首先根據傳進來的類加載器,全部的接口[參數1,參數2]來獲得最終的代理對象的Class對象,在這裏會實現傳進來的接口中的全部方法[Look up or generate the designated proxy class.]io
2.而後獲取代理對象的Class的的構造方法,而且是帶有一個參數類型是{ InvocationHandler.class }的構造方法Constructor對象
而後調用Constructor的newInstance(new Object[] { h });方法建立出代理對象類型爲Object類型
3.而後在初始化代理對象時候經過靜態代碼塊中反射的方式Class.forName("xxx").getMethod("save", new Class[0])把真實的方法獲取到,做爲成員變量保存
4.而後調用代理對象中實現了接口的方法save,在save方法中調用成員變量InvocationHandler h的invoke方法,這樣就進入了咱們自定義的代理類的監控類[實現了InvocationHandler接口]中實現的invoke方法
5.至此整個執行流程結束,完成了代理方法的調用,在代理方法中調用個性化的方法而且也調用了被代理對象的方法自己
示例以下:
核心方法就是如何建立的代理對象,調用的是Proxy類的靜態方法newInstance方法,實現以下:
其中的重點是如何根據類加載器,實現的接口獲得代理對象的Class對象,實現方法在getProxyClass(loader, interfaces)中,具體以下:
上面建立代理類的Class中核心方法是ProxyGenerator.generateProxyClass(proxyName, interfaces);具體的實現能夠點進去看,實際又去調用了ProxyGenerator.generateClassFile()方法,並且有一個成員屬性能夠設置是否把生成的代理類字節碼保存到硬盤上屬性名爲saveGeneratedFiles,設置方式以下:
能夠看下生成的class,而後反編譯以後
反編譯以後以下:
上面就是一個對象被代理的整個過程了.
大體理解下邏輯,Proxy類調用newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
1.首先根據傳進來的類加載器,全部的接口[參數1,參數2]來獲得最終的代理對象的Class對象,在這裏會實現傳進來的接口中的全部方法[Look up or generate the designated proxy class.]
2.而後獲取代理對象的Class的的構造方法,而且是帶有一個參數類型是{ InvocationHandler.class }的構造方法Constructor對象
而後調用Constructor的newInstance(new Object[] { h });方法建立出代理對象類型爲Object類型
3.而後在初始化代理對象時候經過靜態代碼塊中反射的方式Class.forName("xxx").getMethod("save", new Class[0])把真實的方法獲取到,做爲成員變量保存
4.而後調用代理對象中實現了接口的方法save,在save方法中調用成員變量InvocationHandler h的invoke方法,這樣就進入了咱們自定義的代理類的監控類[實現了InvocationHandler接口]中實現的invoke方法
5.至此整個執行流程結束,完成了代理方法的調用,在代理方法中調用個性化的方法而且也調用了被代理對象的方法自己
Spring中的具體的jdk基於接口方式的動態代理的監控類是JdkDynamicAopProxy,他裏邊確定實現了invoke方法,而且實現了InvocationHandler接口,而且提供了getProxy方法,
1.7中一樣的核心入口方法也是Proxy.newInstance(),實現以下
上面的重點是如何獲取代理對象的Class對象,在jdk1.6中的方法名是getProxyClass(loader,interfaces),1.7中進行了封裝在getProxyClass0(loader, intfs)中,具體實現以下:
上面的緩存是proxyClassCache,定義的是一個WeakCache類型的對象,以下:
map是實現緩存的核心變量,是一個嵌套結構(key,sub-key) -> value key是傳入的ClassLoader包裝後的對象,sub-key是WeakCache構造函數傳入的的KeyFactory()生成的,value就是生成的代理類對象是由WeakCache傳入的構造函數ProxyClassFactory生成的,生成sub-key的KeyFactory以下:
Value是傳入的ProxyClassFactory生成的,對應的apply方法其實就是jdk1.6中的getProxyClass方法,以下:
經過sub-key拿到一個Supplier<Class<?>>對象,而後調用get方法獲得代理類的Class對象,而後看proxyClassCache.get(loader,interfaces)方法以下:
經過sub-key獲得supplier,supplier就是這個factory調用他的get方法以下:
1.7沒有1.6的邏輯好理順,可是思路都是同樣的,緩存中獲取,有了就返回,沒有就建立.