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

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

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

    隨筆-126  評論-247  文章-5  trackbacks-0

    動態代理可以提供對另一個對象的訪問,同時隱藏實際對象的具體事實,代理對象對客戶隱藏了實際對象。動態代理可以對請求進行其他的一些處理,在不允許直接訪問某些類,

    或需要對訪問做一些特殊處理等,這時候可以考慮使用代理。目前 Java 開發包中提供了對動態代理的支持,但現在只支持對接口的實現。
     
    主要是通過 java.lang.reflect.Proxy 類和 java.lang.reflect.InvocationHandler 接口。 Proxy 類主要用來獲取動態代理對象,InvocationHandler 接口用來約束調用者行為。

    “寫一個 ArrayList 類的代理,其內部實現和 ArrayList 中完全相同的功能,并可以計算每個方法運行的時間。”這是一份考題上的題目,沒有答案,來看下實現:


    package example;

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    /**
     * -----------------------------------------
     * @描述  TODO
     * @作者  fancy
     * @郵箱  fancydeepin@yeah.net
     * @日期  2012-8-27 <p>
     * -----------------------------------------
     
    */
    public class ProxyApp {


        
    public static void main(String[] args){
            
            
    //ArrayList代理,通過代理計算每個方法調用所需時間
            List<Integer> arrayListProxy = (List<Integer>)Proxy.newProxyInstance(
                ArrayList.
    class.getClassLoader(),   /*定義代理類的類加載器,用于創建代理對象,不一定必須是ArrayList,也可以是其他的類加載器*/
                ArrayList.
    class.getInterfaces(),     /*代理類要實現的接口列表*/
                
    new InvocationHandler() {            /*指派方法調用的調用處理程序,這里用了匿名內部類*/
                    
                    
    private ArrayList<Integer> target = new ArrayList<Integer>(); //目標對象(真正操作的對象)
                    /**
                     * <B>方法描述:</B>
                     * <p style="margin-left:20px;color:#A52A2A;">
                     * 在代理實例上處理方法調用并返回結果
                     * 
    @param proxy     代理對象(注意不是目標對象)
                     * 
    @param method  被代理的方法
                     * 
    @param args         被代理的方法的參數集
                     * 
    @return <span style="color: #008080;"> 返回方法調用結果 </span>
                     
    */
                    @Override
                    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        
                        
    long beginTime = System.currentTimeMillis();  //開始時間
                        TimeUnit.MICROSECONDS.sleep(
    1);
                        Object obj 
    = method.invoke(target, args);          //實際調用的方法,并接受方法的返回值
                        
    long endTime = System.currentTimeMillis();   //結束時間
                        System.out.println(
    "[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");
                        
    return obj;   //返回實際調用的方法的返回值
                        
                    }
                    
                }
            );
            arrayListProxy.add(
    2);
            arrayListProxy.add(
    4);
            System.out.println(
    "--------- 迭代 ---------");
            
    for(int i : arrayListProxy){
                System.out.print(i 
    + "\t");
            }
        }
    }

    后臺打印輸出結果:


    [add] spend 
    2 ms
    [add] spend 
    1 ms
    --------- 迭代 ---------
    [iterator] spend 
    1 ms
    2    4    

    從代碼上來看,用到了匿名內部類,這樣一來,InvocationHandler 只能用一次,如果多個地方都需要用到這樣一個相同的 InvocationHandler,可以將其抽象出來成為一個單獨的類:


    package test;

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.util.concurrent.TimeUnit;

    public class MyInvocationHandler implements InvocationHandler{

        
    private Object target; //目標對象
        
        
    public MyInvocationHandler(Object target){
            
            
    this.target = target;
        }
        
        @Override
        
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            
            
    long beginTime = System.currentTimeMillis();
            TimeUnit.MICROSECONDS.sleep(
    1);
            Object obj 
    = method.invoke(target, args);
            
    long endTime = System.currentTimeMillis();
            System.out.println(
    "[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");
            
    return obj;
            
        }

    }


    客戶端調用改成:


    package example;

    import java.lang.reflect.Proxy;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * -----------------------------------------
     * @描述  TODO
     * @作者  fancy
     * @郵箱  fancydeepin@yeah.net
     * @日期  2012-8-27 <p>
     * -----------------------------------------
     
    */
    public class ProxyApp {


        
    public static void main(String[] args){
            
            
    //ArrayList代理,通過代理計算每個方法調用所需時間
            List<Integer> arrayListProxy = (List<Integer>)Proxy.newProxyInstance(
                ArrayList.
    class.getClassLoader(),     /*定義代理類的類加載器,用于創建代理對象,不一定必須是ArrayList,也可以是其他的類加載器*/
                ArrayList.
    class.getInterfaces(),       /*代理類要實現的接口列表*/
                
    new MyInvocationHandler(new ArrayList<Integer>())         /*指派方法調用的調用處理程序,這里用了匿名內部類*/
            );
            arrayListProxy.add(
    2);
            arrayListProxy.add(
    4);
            System.out.println(
    "--------- 迭代 ---------");
            
    for(int i : arrayListProxy){
                System.out.print(i 
    + "\t");
            }
        }
    }

    從上面代碼看來,客戶端知道代理的實際目標對象,還知道怎么樣去創建這樣一個代理對象,如果想把這些信息全部對客戶端隱藏起來,可以將這些代碼挪到一個類中,將它們封裝起來:


    package example;

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;

    /**
     * -----------------------------------------
     * @描述  TODO
     * @作者  fancy
     * @郵箱  fancydeepin@yeah.net
     * @日期  2012-8-27 <p>
     * -----------------------------------------
     
    */
    public class ProxyUtil {

        
    public enum ArrayListProxy {
            PROXY;
            
            
    private Object target;
            
            ArrayListProxy(){
                
    this.target = new ArrayList<Object>();
            }
            
            
    public List getInstance(){
                
                
    return (List)Proxy.newProxyInstance(ArrayList.class.getClassLoader(), ArrayList.class.getInterfaces(),
                        
    new InvocationHandler() {
                            
                            @Override
                            
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                
                                
    long beginTime = System.currentTimeMillis();
                                TimeUnit.MICROSECONDS.sleep(
    1);
                                Object obj 
    = method.invoke(target, args);
                                
    long endTime = System.currentTimeMillis();
                                System.out.println(
    "[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");
                                
    return obj;
                                
                            }
                        });
            }
        }
    }

    客戶端調用改成:


    package example;

    import java.util.List;
    import example.ProxyUtil.ArrayListProxy;

    /**
     * -----------------------------------------
     * @描述  TODO
     * @作者  fancy
     * @郵箱  fancydeepin@yeah.net
     * @日期  2012-8-27 <p>
     * -----------------------------------------
     
    */
    public class ProxyApp {


        
    public static void main(String[] args){
            
            List
    <Integer> arrayListProxy = ArrayListProxy.PROXY.getInstance();
            arrayListProxy.add(
    2);
            arrayListProxy.add(
    4);
            System.out.println(
    "--------- 迭代 ---------");
            
    for(int i : arrayListProxy){
                System.out.print(i 
    + "\t");
            }
            
        }
    }

    上面代碼中用到了枚舉 enum,如果不想用枚舉,就改用普通類來實現就行了。


      
    posted on 2012-08-27 20:43 fancydeepin 閱讀(6421) 評論(4)  編輯  收藏

    評論:
    # re: java 動態代理(Proxy) 2012-08-28 11:47 | 菠蘿大象
    我想問下,你用枚舉是為了什么?  回復  更多評論
      
    # re: java 動態代理(Proxy) 2012-08-28 19:14 | fancydeepin
    回復:@菠蘿大象

    枚舉列表的每個元素都是一個枚舉對象,它們是靜態的,枚舉的構造子默認是只能內部可用,私有的,這樣一來,防止了外部試圖自己創建對象,取得代理對象只需直接調用 getInstance() 方法而無需自己去創建對象,一般情況下,我們會提供一個靜態工廠方法,用來獲得代理對象,在這里因為目標很明確,就是要實現一個 ArrayList 的代理,所以在這里我用枚舉取代之,并不使用靜態工廠方法,或類成員,或類方法,或成員方法,用這些都能夠取得代理對象,這里的實現只是我的一點想法,如果做的不好的話,請多指教
      回復  更多評論
      
    # re: java 動態代理(Proxy) 2012-10-08 23:43 | distinys
    我想知道怎么關注你。。找不到加關注幾個字啊。。  回復  更多評論
      
    # re: java 動態代理(Proxy) 2012-10-11 15:20 | fancydeepin
    回復 @distinys

    很抱歉,我也沒找得到"關注"二字,感謝你的訪問 ^_^  回復  更多評論
      

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


    網站導航:
     
    主站蜘蛛池模板: 成人人观看的免费毛片| 男人的好看免费观看在线视频| 免费a级毛片视频| 看免费毛片天天看| 亚洲 小说区 图片区 都市| 农村寡妇一级毛片免费看视频| 国产精品免费小视频| 成人久久久观看免费毛片| 国产国拍精品亚洲AV片| 国产精品区免费视频| 666精品国产精品亚洲| 免费毛片a在线观看67194| 亚洲综合色丁香婷婷六月图片| 女人18毛片a级毛片免费| 国产精品亚洲精品日韩电影| 亚洲精品偷拍视频免费观看 | 亚洲AV午夜成人片| 99re在线这里只有精品免费| 亚洲精品视频久久| 在线观看免费成人| www.xxxx.com日本免费| 亚洲AV第一页国产精品| 国产电影午夜成年免费视频 | 亚洲成在人线电影天堂色| 一个人免费观看www视频在线| 亚洲av无码无线在线观看| 亚洲精品视频免费观看| 外国成人网在线观看免费视频| 亚洲国产精品综合久久久| 美女被免费视频网站a国产| 一级做a爰片久久毛片免费看| 亚洲AV永久无码精品| 青草草色A免费观看在线| 美景之屋4在线未删减免费 | 激情小说亚洲图片| 精品国产_亚洲人成在线高清| 波多野结衣免费在线观看| 免费无码午夜福利片69| 亚洲综合激情另类小说区| 小小影视日本动漫观看免费| 91视频免费观看|