程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 理解java動態代理,java動態代理

理解java動態代理,java動態代理

編輯:JAVA綜合教程

理解java動態代理,java動態代理


      java動態代理是java語言的一項高級特性。在平時的項目開發中,可能很難遇到動態代理的案例。但是動態代理在很多框架中起著不可替代的作用,例如Spring的AOP。今天我們就聊一聊java動態代理的實現原理。

     jdk對於動態代理的支持主要依賴於兩個類:Proxy和InvocationHandler。我們先看一下類圖。

 

     

  Subject類是主題類,定義了我要做什麼。我們需要代理的類即實現Subject接口的RealSubject。

  1.InvocationHandler

  InvocationHandler接口是jdk提供的接口,這個接口只有一個方法

 public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

      我們先了解下InvocationHandler這個類是做什麼。以下是java doc

* <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引用,即我們想要真正執行的目標對象。

  2. Method method。Method是java reflection API的一部分。這裡傳入的method對象,是實際被調用的method方法。

  3. Object[] args。這是方法調用時傳入的參數數組。

  了解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方法是生成代理類的關鍵方法,代理類在程序運行的過程中生成,因而叫做動態代理。

  3. 案例

  了解了這兩個最重要的類之後,我們需要通過一個實例來幫助我們更好的理解動態代理的運行機制。

  首先我們創建一個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設計模式》

 

 

作者:mayday芋頭 出處:http://www.cnblogs.com/maypattis/ 本博客中未標明轉載的文章歸作者mayday芋頭和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved