java動態代理是java語言的一項高級特性。在平時的項目開發中,可能很難遇到動態代理的案例。可是動態代理在不少框架中起着不可替代的做用,例如Spring的AOP。今天咱們就聊一聊java動態代理的實現原理。java
jdk對於動態代理的支持主要依賴於兩個類:Proxy和InvocationHandler。咱們先看一下類圖。設計模式
Subject類是主題類,定義了我要作什麼。咱們須要代理的類即實現Subject接口的RealSubject。數組
1.InvocationHandler框架
InvocationHandler接口是jdk提供的接口,這個接口只有一個方法jvm
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
咱們先了解下InvocationHandler這個類是作什麼。如下是java docide
* <p>Each proxy instance has an associated invocation handler.
* When a method is invoked on a proxy instance, the method
* invocation is encoded and dispatched to the {@code invoke}
* method of its invocation handler.
每個代理實例都會和一個invocation handler關聯,準確的說,每個proxy類都會持有一個InvocationHandler實例,而且將目標函數交給InvcationHandler實例去執行。InvocationHandler只有invoke()這個方法,這個方法即實際被調用的方法。無論代理調用的是何種方法,處理器被調用的必定是invoke()方法。下面咱們看看這個方法的參數。函數
1. Object proxy。傳入的Subject引用,即咱們想要真正執行的目標對象。post
2. Method method。Method是java reflection API的一部分。這裏傳入的method對象,是實際被調用的method方法。this
3. Object[] args。這是方法調用時傳入的參數數組。spa
瞭解invoke()方法後,讀者必定想知道,Subject的目標方法是怎麼被調用的呢?接下來咱們繼續瞭解Proxy類。
2. Proxy
接下來咱們瞭解下Proxy類是如何與InvocationHandler一共工做的。java doc中對Proxy的介紹以下:
* provides static methods for creating dynamic proxy
* classes and instances, and it is also the superclass of all
* dynamic proxy classes created by those methods.
Proxy提供了一個靜態方法去建立動態代理類,最經常使用的就是下面這個方法了。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
利用newProxyInstance能夠動態的建立所須要的代理對象,而且和與它關聯的InvocationHandler綁定。參數以下
1. ClassLoader loader, 加載代理類的類加載器。
2. Class<?>[] interfaces, 代理類實現的接口。建立的代理類對象,只能強轉爲該interfaces的子類。
3. InvocationHandler h, 代理類所關聯的InvocationHandler。全部被代理的方法都會經過該InvocationHandler的invoke()方法執行。
newProxyInstance方法是生成代理類的關鍵方法,代理類在程序運行的過程當中生成,於是叫作動態代理。
瞭解了這兩個最重要的類以後,咱們須要經過一個實例來幫助咱們更好的理解動態代理的運行機制。
首先咱們建立一個Subject接口以及其實現類。
步驟1. 定義Subject
1 public interface Subject { 2
3 public void say(String str); 4 } 5
6 public class SubjectBean implements Subject { 7
8 @Override 9 public void say(String str) { 10 System.out.println(str); 11 } 12 }
Subject的say方法是咱們須要代理的方法。在該方法的先後咱們不妨作一些額外的操做。接下來咱們定義咱們的InvocationHandler。
步驟2. 定義InvocationHandler
1 public class MyInvocationHandle implements InvocationHandler { 2
3 Subject subject; 4
5 public MyInvocationHandle(Subject subject) { 6 this.subject = subject; 7 } 8
9 @Override 10 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 11 System.out.println("pre"); 12 method.invoke(subject, args); 13 System.out.println("post"); 14 return null; 15 } 16
17 }
經過構造器,把被代理的對象傳入。
步驟3. 定義生成代理類方法實現
public class Main { public static Subject getProxy(Subject subject){ return (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), new MyInvocationHandle(subject)); } public static void main(String[] args) { Subject subject = new SubjectBean(); Subject proxy = getProxy(subject); proxy.say("hello"); } }
執行main函數,最後輸出的結果爲:
可見,say()函數真正method.invoke(subject, args)這裏完成的。在執行先後能夠加入任意代碼片斷,完成對say()方法的加強操做。
4. debug
咱們對main方法debug看看,proxy類究竟是什麼。以下圖
com.sun.proxy.$Proxy()類,是Proxy.newProxyInstance被調用後在jvm運行時動態生成的一個對象,命名方式都是這樣的形式,以$開頭,proxy爲中,最後一個數字表示對象的標號。至於它爲何能夠轉爲Subject,是由於咱們在傳入的第二個參數中,規定了它的類型信息。
這篇文章主要簡述了java動態代理的實現機制。若有錯誤之處,還望讀者多多指教。
參考文獻:
《Head First設計模式》