接上一篇Spring AOP系列(一)— 代理模式,本篇來聊聊動態代理。html
動態代理與靜態代理的區別
要想了解動態代理與靜態代理的區別,須要有兩個前置知識點:java程序是如何執行的以及類加載機制。java
java程序執行過程
- 將java源碼(.java文件)經過編譯器(javac.exe)編譯成JVM文件(.class文件)。
- 將JVM文件經過java.exe執行,輸出結果。
靜態代理顯示的編寫了代理類,所以編譯過程當中會生成對應的.class文件,最終在運行過程當中執行這些.class文件。而動態代理並未顯示編寫代理類,也並不存在代理類的.class文件,而是在程序運行期間由JVM根據反射等機制動態的生成。
類加載機制
java虛擬機中類加載的全過程,分別是:加載、驗證、準備、解析、初始化。其中「加載」是類加載的第一個步驟,在加載階段,虛擬機須要完成如下3件事情:數據庫
- 經過一個類的全限定名來獲取定義此類的二進制字節流。
- 將這個字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構。
- 在內存中生成一個表明這個類的
java.lang.class
對象,做爲方法區這個類的各類數據訪問入口。
因爲虛擬機規範對這3點要求並不具體,因此實際的實現是很是靈活的。關於第1點,獲取類的二進制字節流(class字節碼)就有不少途徑:
- 從ZIP包獲取,這是JAR、EAR、WAR等格式的基礎。
- 從網絡中獲取,典型的應用是 Applet。
- 運行時計算生成,這種場景使用最多的是動態代理技術,在
java.lang.reflect.Proxy
類中,就是用了 ProxyGenerator.generateProxyClass
來爲特定接口生成形式爲 *$Proxy
的代理類的二進制字節流。
- 由其它文件生成,典型應用是JSP,即由JSP文件生成對應的Class類。
- 從數據庫中獲取等等。
其中「運行時計算生成」,就是「動態代理」技術的實現思路。網絡
小結
靜態代理的優勢
實現簡單,且不侵入原代碼。
靜態代理的缺點數據結構
- 靜態代理要求:代理對象與被代理對象須要實現一致的接口,所以當但願使用一個代理類代理多個被代理類時,能夠經過如下兩種方式:
- 只維護一個代理類,由這個代理類實現多個接口,可是這樣就致使代理類過於龐大。
- 新建多個代理類,每一個目標對象對應一個代理類,可是這樣會產生過多的代理類。
- 當接口須要增長、刪除、修改方法的時候,目標對象與代理類都要同時修改,不易維護。
動態代理的優點不在於省去了編寫代理類的工做量,而是實現了能夠在原始類和接口還未知的時候,就肯定代理類的代理行爲。當代理類與原始類脫離直接聯繫後,就能夠很靈活地重用於不一樣的應用場景之中。
接下來將詳細地介紹動態代理的兩種常見的實現方式:常見的動態代理的實現方式有兩種:JDK動態代理和CGLIB動態代理代理