<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

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

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


    網站導航:
     
    主站蜘蛛池模板: 在线播放免费播放av片| 狼人大香伊蕉国产WWW亚洲| 成人国产精品免费视频| 亚洲综合色区在线观看| 美女无遮挡免费视频网站| 吃奶摸下高潮60分钟免费视频| 亚洲AV无码国产精品永久一区| 精品国产麻豆免费网站| 亚洲男同gay片| 国产18禁黄网站免费观看| 美女被爆羞羞网站在免费观看| 亚洲电影日韩精品| 两个人www免费高清视频| 亚洲爆乳无码一区二区三区| 久久久久久夜精品精品免费啦| 亚洲视频在线观看一区| 久久久高清免费视频| AV激情亚洲男人的天堂国语| 亚洲国产高清在线一区二区三区| 韩国免费A级毛片久久| 亚洲黄色网站视频| 日本免费无遮挡吸乳视频电影| 黄人成a动漫片免费网站| 亚洲人成人网站色www| 中国黄色免费网站| 亚洲av无码电影网| 亚洲国产成人精品无码久久久久久综合 | 亚洲级αV无码毛片久久精品| a级在线免费观看| 亚洲制服丝袜在线播放| 暖暖免费高清日本一区二区三区| 日亚毛片免费乱码不卡一区| 亚洲欧洲日产国产综合网| 女人18毛片a级毛片免费视频| 国产日韩精品无码区免费专区国产| 亚洲欧洲一区二区| 四虎国产精品免费视| 免费人成毛片动漫在线播放| 亚洲另类无码一区二区三区| 超清首页国产亚洲丝袜| 日韩毛片免费无码无毒视频观看|