1.前言
之前對動態代理的技術只是表面上理解,沒有形成一個體系,這裏總結一下,整個動態代理的實現以及實現原理,以表述的更清楚一些。
2.動態代理的實現應用到的技術
1、動態編譯技術,可以使用Java自帶的JavaCompiler類,也可以使用CGLIB、ASM等字節碼增強技術,Java的動態代理包括Spring的內部實現貌似用的都是這個
2、反射,包括對於類.class和getClass()方法的理解,Method類、Constructor類的理解
3、IO流,主要就是字符輸出流FileWriter
4、對於ClassLoader的理解
3.動態代理示例
接口類:
1 2 3 4 |
|
接口實現類:
1 2 3 4 5 6 7 8 9 10 |
|
代理處理類MyInvocationHandler.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
測試類:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
輸出:
1 2 3 4 5 6 |
|
用起來是很簡單,其實這裏基本上就是AOP的一個簡單實現了,目的是在目標對象的方法執行之前和執行之後進行了增強。
Spring的AOP實現其實也是用了Proxy和InvocationHandler這兩個東西的。
4.動態代理原理
下面我們從jdk實現的源代碼的層面分析一下,動態代理產生的整個過程。
上面的程序的入口,便是代理處理類MyInvocationHandler中的getProxy()方法。
1 2 3 4 5 |
|
Proxy.newProxyInstance() 方法,最終將返回一個實現了指定接口的類的實例,
其三個參數分別是:ClassLoader,指定的接口及我們自己定義的InvocationHandler類。我摘幾條關鍵的代碼出來,看看這個代理類的實例對象到底是怎麼生成的。
4.1 Proxy.newProxyInstance的源碼(JDK1.6):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
4.2 我們再去看getProxyClass0()方法的源碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
|
4.3 其中ProxyGenerator.generateProxyClass()的方法是最終生成代理類的字節碼.
ProxyGenerator是sun.misc包中的類,它沒有開源,不過我們可以根據它將生成的代理類的字節碼保存在本地上,然後反編譯查看生成的代理類。
具體請參照地址:http://blog.csdn.net/mhmyqn/article/details/48474815
4.4 反編譯生成的$Proxy0.class代理類文件
下面從網上copy的一個代理類的反編譯文件,對比可以看一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
|
由此總結一下動態代理實現過程。
1.通過 Proxy.newProxyInstance() 方法,返回一個繼承Proxy類,並且最終實現了指定接口的代理類的實例。
在這裏分爲兩個大的步驟:
- 通過getProxyClass0()方法生成代理類。在這個方法裏面,
- ProxyGenerator.generateProxyClass()的方法是最終生成代理類的字節碼.
- defineClass0()方法把相應的字節碼生成代理類
2. 調用 newInstance(Constructor<?> cons, InvocationHandler h)方法 創建一個新的代理類實例,創建對象時,傳入我們定義好的代理處理類,InvocationHandle類。
2. 調用新實例的方法,即此例中的add(), update()方法,即原InvocationHandler類中的invoke()方法。
5.動態代理的優點
1、最直觀的,類少了很多
2、代理內容也就是InvocationHandler接口的實現類可以複用,可以給A接口用、也可以給B接口用,A接口用了InvocationHandler接口實現類A的代理,不想用了,可以方便地換成InvocationHandler接口實現B的代理
3、最重要的,用了動態代理,就可以在不修改原來代碼的基礎上,就在原來代碼的基礎上做操作,這就是AOP即面向切面編程
6.動態代理的缺點
動態代理的缺點,就是前面我們讀源代碼的時候遇到的。它只能針對接口生成代理,不能只針對某一個類生成代理。
如果需要爲某一個單獨的類實現一個代理的話,考慮使用CGLIB等第三方字節碼(一種字節碼增強技術)。
參考地址:http://blog.csdn.net/zhangerqing/article/details/42504281/
http://www.cnblogs.com/xrq730/p/4907999.html
http://blog.csdn.net/mhmyqn/article/details/4847481516:23:20