Java動態代理

來源:互聯網
上載者:User

標籤:

 

代理的基本構成:

      代理模式上,基本上有Subject角色,RealSubject角色,Proxy角色。其中:Subject角色負責定義RealSubject和Proxy角色應該實現的介面;RealSubject角色用來真正完成商務服務功能;Proxy角色負責將自身的Request請求,調用realsubject 對應的request功能來實現業務功能,自己不真正做業務。

                                                      

 

       上面的這幅代理結構圖是典型的靜態代理模式:

       當在代碼階段規定這種代理關係,Proxy類通過編譯器編譯成class檔案,當系統運行時,此class已經存在了。這種靜態代理模式固然在訪問無法訪問的資源,增強現有的介面業務功能方面有很大的優點,但是大量使用這種靜態代理,會使我們系統內的類的規模增大,並且不易維護;並且由於Proxy和RealSubject的功能 本質上是相同的,Proxy只是起到了中介的作用,這種代理在系統中的存在,導致系統結構比較臃腫和鬆散。

             為瞭解決這個問題,就有了動態地建立Proxy的想法:在運行狀態中,需要代理的地方,根據Subject 和RealSubject,動態地建立一個Proxy,用完之後,就會銷毀,這樣就可以避        免了Proxy 角色的class在系統中冗雜的問題了。

 

InvocationHandler角色的由來:

        仔細思考代理模式中的代理Proxy角色。Proxy角色在執行代理業務的時候,無非是在調用真正業務之前或者之後做一些“額外”業務。

                                  

 

     有可以看出,代理類處理的邏輯很簡單:在調用某個方法前及方法後做一些額外的業務。換一種思路就是:在觸發(invoke)真實角色的方法之前或者之後做一些額外的業務。那            麼,為了構造出具有通用性和簡單性的代理類,可以將所有的觸發真實角色動作交給一個觸發的管理器,讓這個管理器統一地管理觸發。這種管理器就是Invocation Handler。

     動態代理模式的結構跟上面的靜態代理模式稍微有所不同,多引入了一個InvocationHandler角色。      

     先解釋一下InvocationHandler的作用:                                                                

在靜態代理中,代理Proxy中的方法,都指定了調用了特定的realSubject中的對應的方法:

在上面的靜態代理模式下,Proxy所做的事情,無非是調用在不同的request時,調用觸發realSubject對應的方法;更抽象點看,Proxy所作的事情;在Java中 方法(Method)也是作為一個對象來看待了,

     動態代理工作的基本模式就是將自己的方法功能的實現交給 InvocationHandler角色,外界對Proxy角色中的每一個方法的調用,Proxy角色都會交給InvocationHandler來處理,而            InvocationHandler則調用具體對象角色的方法。如所示:

                                  

     在這種模式之中:代理Proxy 和RealSubject 應該實現相同的功能,這一點相當重要。(我這裡說的功能,可以理解為某個類的public方法)

     在物件導向的編程之中,如果我們想要約定Proxy 和RealSubject可以實現相同的功能,有兩種方式:

    a.一個比較直觀的方式,就是定義一個功能介面,然後讓Proxy 和RealSubject來實現這個介面。

    b.還有比較隱晦的方式,就是通過繼承。因為如果Proxy 繼承自RealSubject,這樣Proxy則擁有了RealSubject的功能,Proxy還可以通過重寫RealSubject中的方法,來實現多態。

         其中JDK中提供的建立動態代理的機制,是以a 這種思路設計的,而cglib 則是以b思路設計的。

     

JDK的動態代理建立機制----通過介面:

  比如現在想為RealSubject這個類建立一個動態代理對象,JDK主要會做以下工作:

    1.   擷取 RealSubject上的所有介面列表;
    2.   確定要產生的代理類的類名,預設為:com.sun.proxy.$ProxyXXXX ;

    3.   根據需要實現的介面資訊,在代碼中動態建立 該Proxy類的位元組碼;

    4 .  將對應的位元組碼轉換為對應的class 對象;

    5.   建立InvocationHandler 執行個體handler,用來處理Proxy所有方法調用;

    6.   Proxy 的class對象 以建立的handler對象為參數,執行個體化一個proxy對象

 

JDK通過 java.lang.reflect.Proxy包來支援動態代理,一般情況下,我們使用下面的newProxyInstance方法

static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
          返回一個指定介面的代理類執行個體,該介面可以將方法調用指派到指定的調用處理常式。

而對於InvocationHandler,我們需要實現下列的invoke方法:

在調用代理對象中的每一個方法時,在代碼內部,都是直接調用了InvocationHandler 的invoke方法,而invoke方法根據代理類傳遞給自己的method參數來區分是什麼方法。

 Object invoke(Object proxy,Method method,Object[] args)
          在代理執行個體上處理方法調用並返回結果。

 

cglib 產生動態代理類的機制----通過類繼承:

 

JDK中提供的產生動態代理類的機制有個鮮明的特點是: 某個類必須有實現的介面,而產生的代理類也只能代理某個類介面定義的方法!更極端的情況是:如果某個類沒有實現介面,那麼這個類就不能同JDK產生動態代理了!

      幸好我們有cglib。“CGLIB(Code Generation Library),是一個強大的,高效能,高品質的Code產生類庫,它可以在運行期擴充Java類與實現Java介面。”

cglib 建立某個類A的動態代理類的模式是:

1.   尋找A上的所有非final 的public類型的方法定義;

2.   將這些方法的定義轉換成位元組碼;

3.   將組成的位元組碼轉換成相應的代理的class對象;

4.   實現 MethodInterceptor介面,用來處理 對代理類上所有方法的請求(這個介面和JDK動態代理InvocationHandler的功能和角色是一樣的)

package com.sunchao.cglibproxy;import java.lang.reflect.Method;import com.sunchao.jdkdyproxy.*;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class CglibProxy {        public static Subject createCglibDynamicProxy(final Object delegate) {        Enhancer enhancer = new Enhancer();        enhancer.setCallback(new CglibInterceptor(delegate));        enhancer.setInterfaces(new Class<?>[]{Subject.class});        Subject cglibProxy = (Subject) enhancer.create();        return cglibProxy;    }        private static class CglibInterceptor implements MethodInterceptor {        final private Object delegate;                CglibInterceptor(Object delegate) {            this.delegate =delegate;        }                @Override        public Object intercept(Object arg0, Method arg1, Object[] arg2,                MethodProxy arg3) throws Throwable {            //System.out.println("aop before do with the request!");            return arg1.invoke(delegate, arg2);        //    System.out.println("aop before do with the request!");            //return null;        }    }    public static void main(String args[]) {        Subject realSubject = new RealSubject();        Subject cglibProxy = createCglibDynamicProxy(realSubject);        cglibProxy.request();            }}

 

原文請見:http://blog.csdn.net/luanlouis/article/details/24589193

Java動態代理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.