<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模式。代理對象為其他對象提供一種代理以控制對這個對象的訪問。它靜態(tài)結(jié)構(gòu)如下:
    Client 需要訪問 RealSubject 時,它實際訪問的是 Proxy 對象,而后 Proxy 對象將請求委托給 RealSubject RealSubject 實現(xiàn)了主要的邏輯, Proxy 對象可以在處理請求之前、之后作額外的處理。可以看出, Proxy RealSubject 實現(xiàn)了同樣的接口,這樣 Client 才可以調(diào)用 RealSubject 實現(xiàn)的所有 Subject 的方法。
    我們在實現(xiàn) Proxy 時,如果使用的是 C++ 語言,我們可以重載操作符 -> 來實現(xiàn)代理。優(yōu)點是實現(xiàn)簡單,缺點是它不能區(qū)別對待不同的請求。當(dāng)然也可以是用普通的形式,創(chuàng)建一個代理類,實現(xiàn)接口,并將調(diào)用委托給被代理的對象。
    如果使用的是 Java 語言,我們當(dāng)然可以使用普通的形式來實現(xiàn) Proxy 模式。但是 JDK1.3 引入了 dynamic proxy ,它允許我們更容易的實現(xiàn)代理。
    二、 JDK中的Dynamic Proxy介紹
    它由 java.lang.reflect.Proxy java.lang.reflect.InvocationHandler 等組成。 Proxy 類擁有一個 protected InvocationHandler 類型的成員變量。 它只能代理 Interface。
    它的基本思想如下:
    1.???? 代理類由 Proxy 的靜態(tài)方法 getProxyClass 來動態(tài)的創(chuàng)建出來。該方法所需要的一個參數(shù)為它所代理的接口數(shù)組。創(chuàng)建出來的代理類實現(xiàn)了所有的接口,并且繼承了 Proxy
    2.???? 代理類實現(xiàn)的接口方法的處理邏輯為,調(diào)用父類的 InvocationHandler 類型的成員變量的 invoke 方法。
    由此可以看出,必須讓 Proxy 對象擁有一個正確的 InvocationHandler 的實現(xiàn)。 Proxy 對象由 Proxy 的靜態(tài)成員函數(shù) newProxyInstance 來創(chuàng)建,該函數(shù)的最后一個參數(shù)為 InvocationHandler 類型。動態(tài)生成的代理類實現(xiàn)的所有接口方法都被委托給 InvocationHandler 接口的 invoke 方法。
    三、 例子代碼
    假如有如下接口:
    interface Foo {
    ?void f(String s);
    ?void g(int i);
    ?String h(int i, String s);
    }
    并且有一個實現(xiàn)
    class Implement implements Foo {
    ?? …
    }
    現(xiàn)在我們想在 Foo 接口的每個方法調(diào)用時,加入日至。一個很簡單很直觀的方法如下:
    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”);
    可以看出這樣的實現(xiàn)代碼很多,而且?guī)缀醵际窍嗤摹.?dāng)然可以編寫程序來寫出這樣的代碼,但是我們?nèi)绻褂?/span> JDK1.3 引入的 dynamic proxy ,那么情況就完全不同了。
    四、 dynamic proxy實現(xiàn)Log的代碼
    1.?????? 編寫 InvocationHandler 的子類,來攔截所有的方法調(diào)用。
    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的靜態(tài)方法來創(chuàng)建代理類。?
    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.?????? 客戶在代理類上調(diào)用方法
    proxy. h( 10 , “str”);
    可以看出,如果接口中有很多方法,那么使用 dynamic proxy 是很合適的,但是如果接口只有很少的方法,可能使用普通的方法更直觀,也更簡單。
    五、 應(yīng)用例子
    如果我們設(shè)計一個數(shù)據(jù)庫連接池,接口如下:
    interface DBConnectionPool {
    ??????????? public java.sql.Connection getConnection() ;
    ??????????? public void releaseConnection( java.sql.Connection conn ) ;
    }
    class DBConnectionPoolImpl implements DBConnectionPool {
    ??????????? …
    }
    ?
    那么一個可能的用戶調(diào)用序列如下:
    void getData() {
    ??????????? DBConnectionPoolImpl?cpi = new DBConnectionPoolImpl() ;
    ??????????? Connection conn = cpi.getConnection() ;
    ??????????? // use conn to retrieve data from db
    ??????????? …
    ??????????? cpi. releaseConnection( conn ) ;
    ???????????
    }
    藍(lán)色的代碼表示了將連接還給連接池,因為所有的連接都是由連接池來管理的。但是這樣的代碼對用戶來講可能不太習(xí)慣,而且迫使用戶這樣編寫代碼,用戶會意識到 cpi 對連接作了特殊的處理。
    ??????????? 一個更好的方法是調(diào)用 Connection 接口的 close 方法。這樣的代碼如下:
    void getData() {
    ??????????? DBConnectionPoolImpl?cpi = new DBConnectionPoolImpl() ;
    ??????????? Connection conn = cpi.getConnection() ;
    ??????????? // use conn to retrieve data from db
    ??????????? …
    ??????????? conn.close() ;
    }
    這樣更符合普通用戶的編碼習(xí)慣。但是可以這么編碼的前提是:
    1、 close 函數(shù)要將連接對象還給連接池,而不是關(guān)閉物理的數(shù)據(jù)庫連接。
    2、 所有 Connection 的其他函數(shù)必須能夠正常工作。
    也就是說需要特殊處理 close 函數(shù),而對其他函數(shù)直接進(jìn)行轉(zhuǎn)發(fā)就可以了。
    用最直接的方法實現(xiàn)如下:
    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接口中的方法轉(zhuǎn)發(fā)
    }
    可以看出這樣的實現(xiàn)代碼很多,而且?guī)缀醵际窍嗤摹.?dāng)然可以編寫程序來寫出這樣的代碼,如果使用 DynamicProxy ,那么整個實現(xiàn)就比較優(yōu)雅了。
    ?
    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 返回動態(tài)代理即可。實現(xiàn)如下:
    class DBConnectionPoolImpl implements DBConnectionPool {
    ??????????? public Connection getConnection() {
    ??????????????????????? Connection conn?;
    ??????????????????????? // 從池中取得連接或建立連接
    ??????????????????????? return (Connection)Proxy.newInstance(
    ????? ????????????? Connection.class.getClassLoader(),
    ??? ????????????????????? new Class[]{ Connection.class },
    ???????????? ?????? new ConnectionProxy( conn ) ?) ;
    ?
    }
    }
    這樣就實現(xiàn)了連接池。
    jdk1.5 提供的用于 rmi dynamic stub 也使用 dynamic proxy 技術(shù)。只要你認(rèn)真研究,其實很多問題都可以使用 dynamic proxy 來解決。

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


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


    網(wǎng)站導(dǎo)航:
     

    導(dǎo)航

    統(tǒng)計

    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    介紹 IOC

    友情鏈接

    最新隨筆

    搜索

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲卡一卡二卡乱码新区| 亚洲噜噜噜噜噜影院在线播放| 成a人片亚洲日本久久| 无码少妇一区二区浪潮免费| 亚洲精品视频在线| 国产一区二区免费| 亚洲午夜免费视频| 外国成人网在线观看免费视频| 亚洲VA中文字幕无码一二三区 | 亚洲成在人线aⅴ免费毛片| 久久综合亚洲色HEZYO社区| 免费v片在线观看视频网站| 亚洲六月丁香六月婷婷色伊人| 成年网站免费视频A在线双飞| 国产精品亚洲自在线播放页码| 精品熟女少妇AV免费观看| 亚洲AV性色在线观看| 又粗又硬又大又爽免费视频播放| 婷婷国产偷v国产偷v亚洲| 久久国产成人精品国产成人亚洲| 国产线视频精品免费观看视频| 亚洲一区综合在线播放| 黄页网站在线看免费| 国产亚洲精彩视频| 国产综合精品久久亚洲| 97精品免费视频| 亚洲综合精品伊人久久| 免费一区二区视频| 亚洲成人免费在线| 亚洲精品无码专区在线播放| 亚洲中文字幕成人在线| 久久久久久一品道精品免费看| 亚洲综合精品第一页| 亚洲欭美日韩颜射在线二| 在线观看永久免费| 黄色a三级三级三级免费看| 久久久亚洲精品国产| 成人免费777777| 国产一级黄片儿免费看| 亚洲av乱码一区二区三区| 国产av无码专区亚洲国产精品|