<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    seaairland

     

    Dynamic Proxy介紹

    一、 proxy模式簡介
    GoF介紹了proxy模式。代理對象為其他對象提供一種代理以控制對這個對象的訪問。它靜態結構如下:
    Client 需要訪問 RealSubject 時,它實際訪問的是 Proxy 對象,而后 Proxy 對象將請求委托給 RealSubject RealSubject 實現了主要的邏輯, Proxy 對象可以在處理請求之前、之后作額外的處理。可以看出, Proxy RealSubject 實現了同樣的接口,這樣 Client 才可以調用 RealSubject 實現的所有 Subject 的方法。
    我們在實現 Proxy 時,如果使用的是 C++ 語言,我們可以重載操作符 -> 來實現代理。優點是實現簡單,缺點是它不能區別對待不同的請求。當然也可以是用普通的形式,創建一個代理類,實現接口,并將調用委托給被代理的對象。
    如果使用的是 Java 語言,我們當然可以使用普通的形式來實現 Proxy 模式。但是 JDK1.3 引入了 dynamic proxy ,它允許我們更容易的實現代理。
    二、 JDK中的Dynamic Proxy介紹
    它由 java.lang.reflect.Proxy java.lang.reflect.InvocationHandler 等組成。 Proxy 類擁有一個 protected InvocationHandler 類型的成員變量。 它只能代理 Interface。
    它的基本思想如下:
    1.???? 代理類由 Proxy 的靜態方法 getProxyClass 來動態的創建出來。該方法所需要的一個參數為它所代理的接口數組。創建出來的代理類實現了所有的接口,并且繼承了 Proxy
    2.???? 代理類實現的接口方法的處理邏輯為,調用父類的 InvocationHandler 類型的成員變量的 invoke 方法。
    由此可以看出,必須讓 Proxy 對象擁有一個正確的 InvocationHandler 的實現。 Proxy 對象由 Proxy 的靜態成員函數 newProxyInstance 來創建,該函數的最后一個參數為 InvocationHandler 類型。動態生成的代理類實現的所有接口方法都被委托給 InvocationHandler 接口的 invoke 方法。
    三、 例子代碼
    假如有如下接口:
    interface Foo {
    ?void f(String s);
    ?void g(int i);
    ?String h(int i, String s);
    }
    并且有一個實現
    class Implement implements Foo {
    ?? …
    }
    現在我們想在 Foo 接口的每個方法調用時,加入日至。一個很簡單很直觀的方法如下:
    class LogProxy implements Foo {
    private Foo delegate ;
    ?? public LogProxy( Foo foo ) {
    ????????? delegate = foo ;
    }
    public String h(int i, String s) {
    ????? System.out.println(“call h begin ”) ;
    ????? String result = delegate.h( i , s ) ;
    ????? System.out.println(“call h end ”) ;
    ????? Return result ;
    }
    }
    new LogProxy( new Implement()   ).h( 10 , “str”);
    可以看出這樣的實現代碼很多,而且幾乎都是相同的。當然可以編寫程序來寫出這樣的代碼,但是我們如果使用 JDK1.3 引入的 dynamic proxy ,那么情況就完全不同了。
    四、 dynamic proxy實現Log的代碼
    1.?????? 編寫 InvocationHandler 的子類,來攔截所有的方法調用。
    class LogProxy implements InvocationHandler {
    ????? public LogProxy( Object object ) { obj = object ; }
    ????? public Object invoke(Object proxy, Method method, Object[] args)
    ????? throws Throwable {??
    String methodName = method.getName() ;
    System.out.println("call " + methodName?+ “ begin “ ) ;???????
    ?????? ??? Object result = method.invoke( obj , args )?;
    System.out.println("call " + methodName + “ end“ ) ;???????
    ??? ?????? Return result ;
    ????? }
    ????? public Object obj = null ;
    }
    2.?????? 使用 Proxy的靜態方法來創建代理類。?
    LogProxy dp = new LogProxy( new Implment() ) ;
    Foo proxy = (Foo) Proxy.newProxyInstance(
    ??????????? ????????// [1] class loader
    ????? ????????????? Foo.class.getClassLoader(),
    ?????????????????? // [2] interface's Class array
    ?????? ?????????????????? new Class[]{ Foo.class },
    ?????? ?????????????????? // [3] InvocationHandler
    ?????????????????? dp ) ;
    3.?????? 客戶在代理類上調用方法
    proxy. h( 10 , “str”);
    可以看出,如果接口中有很多方法,那么使用 dynamic proxy 是很合適的,但是如果接口只有很少的方法,可能使用普通的方法更直觀,也更簡單。
    五、 應用例子
    如果我們設計一個數據庫連接池,接口如下:
    interface DBConnectionPool {
    ??????????? public java.sql.Connection getConnection() ;
    ??????????? public void releaseConnection( java.sql.Connection conn ) ;
    }
    class DBConnectionPoolImpl implements DBConnectionPool {
    ??????????? …
    }
    ?
    那么一個可能的用戶調用序列如下:
    void getData() {
    ??????????? DBConnectionPoolImpl?cpi = new DBConnectionPoolImpl() ;
    ??????????? Connection conn = cpi.getConnection() ;
    ??????????? // use conn to retrieve data from db
    ??????????? …
    ??????????? cpi. releaseConnection( conn ) ;
    ???????????
    }
    藍色的代碼表示了將連接還給連接池,因為所有的連接都是由連接池來管理的。但是這樣的代碼對用戶來講可能不太習慣,而且迫使用戶這樣編寫代碼,用戶會意識到 cpi 對連接作了特殊的處理。
    ??????????? 一個更好的方法是調用 Connection 接口的 close 方法。這樣的代碼如下:
    void getData() {
    ??????????? DBConnectionPoolImpl?cpi = new DBConnectionPoolImpl() ;
    ??????????? Connection conn = cpi.getConnection() ;
    ??????????? // use conn to retrieve data from db
    ??????????? …
    ??????????? conn.close() ;
    }
    這樣更符合普通用戶的編碼習慣。但是可以這么編碼的前提是:
    1、 close 函數要將連接對象還給連接池,而不是關閉物理的數據庫連接。
    2、 所有 Connection 的其他函數必須能夠正常工作。
    也就是說需要特殊處理 close 函數,而對其他函數直接進行轉發就可以了。
    用最直接的方法實現如下:
    class ConnectionProxy implements Connection {
    ??????????? private Connection realConn ;
    ??????????? private DBConnectionPool dbcp ;
    ??????????? public ConnectionProxy( Connection conn?,?DBConnectionPool pool ) {
    ??????????????????????? realConn = conn ;
    ??????????????????????? dbcp = pool ;
    }
    ?
    public void close() throws SQLException {
    ????????? dbcp. releaseConnection( realConn ) ;
    }
    ?
    public PreparedStatement prepareStatement(String sql, String columnNames[]) throws SQLException {
    ?????????
    ????????? return realConn.prepareStatement( sql , columnNames ) ;
    }
    //??????? 所有的其他Connection接口中的方法轉發
    }
    可以看出這樣的實現代碼很多,而且幾乎都是相同的。當然可以編寫程序來寫出這樣的代碼,如果使用 DynamicProxy ,那么整個實現就比較優雅了。
    ?
    Classs ConnectionProxy InvocationHandler {
    ?? Connection conn ;
    ?? DBConnectionPool cp ;
    Public ConnectionProxy( Connection conn , DBConnectionPool cp ) {
    This.conn = conn ;
    This.cp = cp ;
    }
    public Object invoke(Object proxy, Method method, Object[] args)
    ????? throws Throwable {
    ???????????? Object result = null ;
    ???????????? if ( “close”.equals( method.getName()?) {
    ?????????????????? cp. releaseConnection( conn ) ;
    } else {
    ?????? ??? ?result = method.invoke( obj , args )?;
    }
    ?????????? Return result ;
    ????? }
    }
    有個類 ConnectionProxy后,我們只需要讓 DBConnectionPool 的方法 getConnection 返回動態代理即可。實現如下:
    class DBConnectionPoolImpl implements DBConnectionPool {
    ??????????? public Connection getConnection() {
    ??????????????????????? Connection conn?;
    ??????????????????????? // 從池中取得連接或建立連接
    ??????????????????????? return (Connection)Proxy.newInstance(
    ????? ????????????? Connection.class.getClassLoader(),
    ??? ????????????????????? new Class[]{ Connection.class },
    ???????????? ?????? new ConnectionProxy( conn ) ?) ;
    ?
    }
    }
    這樣就實現了連接池。
    jdk1.5 提供的用于 rmi dynamic stub 也使用 dynamic proxy 技術。只要你認真研究,其實很多問題都可以使用 dynamic proxy 來解決。

    posted on 2006-03-24 13:34 chenhui 閱讀(841) 評論(0)  編輯  收藏 所屬分類: 設計模式


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     

    導航

    統計

    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    介紹 IOC

    友情鏈接

    最新隨筆

    搜索

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产成人精品日本亚洲11| 免费人成大片在线观看播放电影 | 久青草视频97国内免费影视| 亚洲AV日韩AV天堂一区二区三区| 1000部拍拍拍18勿入免费视频软件| 亚洲最大的成人网| 伊人久久大香线蕉亚洲五月天 | 久久亚洲色一区二区三区| 99视频有精品视频免费观看| 伊人久久亚洲综合影院首页| 国产亚洲精品线观看动态图| 精品无码国产污污污免费网站| WWW亚洲色大成网络.COM| 亚洲欧洲日产国码无码久久99| 久久经典免费视频| 一级做a免费视频观看网站| 91亚洲一区二区在线观看不卡 | 国内自产拍自a免费毛片| 两性色午夜免费视频| 久久亚洲国产成人影院| 亚洲精品无码不卡在线播HE| 18禁超污无遮挡无码免费网站国产| 精精国产www视频在线观看免费| 亚洲国产成人精品激情| 亚洲AV本道一区二区三区四区 | 国产av无码专区亚洲国产精品| 免费A级毛片无码A∨免费| h片在线播放免费高清| 亚洲不卡中文字幕| 久久精品国产精品亚洲色婷婷 | 亚洲国产美女精品久久| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 免费国产成人高清在线观看麻豆 | 亚洲人成7777| 亚洲国产香蕉碰碰人人| 亚洲精品天堂成人片?V在线播放| 精品香蕉在线观看免费| 女人体1963午夜免费视频| 人妖系列免费网站观看| 亚洲色大成网站www| 亚洲春色在线观看|