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

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

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

    隨筆 - 45, 文章 - 6, 評論 - 4, 引用 - 0
    數據加載中……

    實現自己的攔截器框架

    AOP技術是spring框架的一個重要特征。通過該特性能夠在函數運行之前,之后,或者異常處理的時候執行我們需要的一些操作。

    下面我們就是需要拋開AOP,Spring這樣成型的框架不用,而僅僅使用java反射機制中的Proxy,InvocationHandler來實現類似Spring框架的攔截器的效果。

    動態代理DynamicProxy

    首先,在設計這個攔截器框架之前,我們需要明白java中動態代理是什么?我想如果早就清楚請直接跳過,如果需要了解,那我想你手邊最好有一個javadoc的電子書。

    Java.lang.reflect.Proxy是反射包的成員之一。具體說明請查javadoc。
    用法就是比如有一個對象,我們需要在調用它提供的方法之前,干點別的什么,就不能直接調用它,而是生成一個它的代理,這個代理有這個對象所提供的所有接口方法,我們通過直接調用代理的這些方法,來實現:函數既能像原來對象的那樣工作,又能在函數運行過程前后加入我們自己的處理。

    這個類有個非常重要的函數用來實現某個類的代理:

    1Object java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader, 
    2             Class<?>
    [] interfaces, 
    3             InvocationHandler h) throws IllegalArgumentException

    參數有點迷惑人,解釋下:
    ClassLoader 是類加載器,這個參數用來定義代理類,一般使用原對象的即可,也可以為null用上下文解決。
    Class<?>[] 接口數組,就是我們需要這個代理能夠提供原來的類的什么函數。如果全部則直接class.getInterfaces()來解決.
    InvocationHandler 調用處理器,這個就是如果你調用代理的方法,那么這個處理器就會被關聯過來,處理調用這個函數的整個過程。這個接口只定義了一個方法:
     
    1public Object invoke(Object proxy, Method method,    
    2                  Object[] args) throws Throwable;  

    參數中proxy就是你調用的代理,method指的是你調用的代理的那個方法,args是傳給該方法的參數。

    我們生成某個類的代理步驟,一般需要先考慮我們在調用這個類的函數的時候(之前,或者之后)如何處理某些事情,因此我們首先考慮的就是如何實現InvocationHandler這個接口。

    讓我們做一個實踐,做這么一個調用處理器:任何使用此處理器的代理在調用它的任何方法的時候,都打印被代理的類的類名+“.”+方法名+”(“+參數+”,”+參數+...+”)”

    步驟1: 定義接口IUser
    1package com.cyh.proxy.sample;   
    2
      
    3public interface IUser 
    {   
    4    public
     String getName();   
    5
      
    6    public void
     setName(String name);   
    7}
      

    步驟2: 寫IUser接口的實現類User

     1 package com.cyh.proxy.sample.impl;   
     2 
      
     3 import
     com.cyh.proxy.sample.IUser;   
     4 
      
     5 public class User implements
     IUser {   
     6 
        String name;   
     7 
      
     8     public
     User(String name) {   
     9     this.name =
     name;   
    10 
        }   
    11 
      
    12     public
     String getName() {   
    13     return
     name;   
    14 
        }   
    15 
      
    16     public void
     setName(String name) {   
    17     this.name =
     name;   
    18 
        }   
    19 }  

    步驟3: 寫TraceHandler實現調用處理器InvocationHandler,即在invoke()方法里我們要打印被代理的類的類名+“.”+方法名+”(“+參數+”,”+參數+...+”)”
     1 package com.cyh.proxy.sample.impl;   
     2 
      
     3 import
     java.lang.reflect.InvocationHandler;   
     4 import
     java.lang.reflect.Method;   
     5 
      
     6 public class TraceHandler implements
     InvocationHandler {   
     7     private
     Object target;   
     8 
      
     9     public
     TraceHandler(Object target) {   
    10     this.target =
     target;   
    11 
        }   
    12 
      
    13     public
     Object invoke(Object proxy, Method method, Object[] args)   
    14         throws
     Throwable {   
    15 
      
    16     // print implicit argument   

    17     System.out.print(target.getClass().getName());   
    18     // print method name   

    19     System.out.print("." + method.getName() + "(");   
    20     // print explicit arguments   

    21     if (args != null) {   
    22         for (int i = 0; i < args.length; i++
    ) {   
    23 
            System.out.print(args[i]);   
    24         if (i < args.length - 1
    ) {   
    25             System.out.print(","
    );   
    26 
            }   
    27 
            }   
    28 
        }   
    29     System.out.println(")"
    );   
    30 
      
    31     return method.invoke(this
    .target, args);   
    32 
        }   
    33 }  

    步驟4: 最后,讓我們寫測試類ProxyTest
     1 package com.cyh.proxy.sample.test;   
     2 
      
     3 import
     java.lang.reflect.InvocationHandler;   
     4 import
     java.lang.reflect.Proxy;   
     5 
      
     6 import
     com.cyh.proxy.sample.IUser;   
     7 import
     com.cyh.proxy.sample.impl.TraceHandler;   
     8 import
     com.cyh.proxy.sample.impl.User;   
     9 
      
    10 public class
     ProxyTest {   
    11 
        User user;   
    12 
      
    13     public
     ProxyTest() {   
    14     user = new User("LaraCroft"
    );   
    15 
      
    16     ClassLoader classLoader =
     user.getClass().getClassLoader();   
    17     Class[] interfaces =
     user.getClass().getInterfaces();   
    18     InvocationHandler handler = new
     TraceHandler(user);   
    19     IUser proxy =
     (IUser) Proxy.newProxyInstance(classLoader, interfaces,   
    20 
            handler);   
    21 
      
    22     proxy.setName("David Beckham"
    );   
    23 
        }   
    24 
      
    25     public static void
     main(String[] args) {   
    26     new
     ProxyTest();   
    27 
        }   
    28 
      
    29 }  

    好了,所有代碼寫好了,運行一下,測試結果是:
    com.cyh.proxy.impl.User.setName(David Beckham)

    講一下運行原理:
    首先我們初始化了user對象,user.name = = “LaraCroft”;
    然后創建了user對象的代理proxy。
    注意這里:
    Proxy.newProxyInstance()函數的返回值使用接口IUser轉型的,你或許會想到
    用User來做強制類型轉換,但是會拋出下面的異常

    Exception in thread "main" java.lang.ClassCastException: $Proxy0 cannot be cast to com.cyh.proxy.impl.User
    因為:代理類是實現了User類的所有接口,但是它的類型是$Proxy0,不是User。

    最后,我們調用代理的setName()方法:
    proxy.setName("David Beckham");

    代理在執行此方法的時候,就好觸發調用處理器 TraceHandler,并執行 TraceHandler的invoke()方法,然后就會打印:
    com.cyh.proxy.impl.User.setName(David Beckham)


    攔截器框架的實現


    好了,關于代理的知識我們講完了,我們可以考慮如何實現這個攔截器的框架,所謂攔截器就是在函數的運行前后定制自己的處理行為,也就是通過實現InvocationHandler達到的。


    設計思路


    我們來理清一下思路,在使用一個攔截器的時候?什么是不變的,什么是變化的?

    不變的:
    每次都要創建代理
    攔截的時間:函數執行之前,之后,異常處理的時候

    變化的:
    每次代理的對象不同
    攔截器每次攔截到執行時的操作不同

    好了,廢話少說,看類圖:



    圖中:
    DynamicProxyFactory 和它的實現類,是一個工廠,用來創建代理

    Interceptor 這個接口用來定義攔截器的攔截處理行為配合DynamicProxyInvocationHandler達到攔截效果
    DynamicProxyInvocationHandler 調用處理器的實現,它有兩個成員,一個是Object target指的是被代理的類,另一個是Interceptor interceptor就是在invoke()方法執行target的函數之前后,異常處理時,調用interceptor的實現來達到攔截,并處理的效果。


    代碼實現

    步驟1: 定義接口DynamicProxyFactory

     1 package com.cyh.proxy.interceptor;   
     2 
      
     3 public interface
     DynamicProxyFactory {   
     4     /**
      
     5 
         * 生成動態代理,并且在調用代理執行函數的時候使用攔截器  
     6 
         *   
     7      * @param
     clazz  
     8 
         *            需要實現的接口  
     9      * @param
     target  
    10 
         *            實現此接口的類  
    11      * @param
     interceptor  
    12 
         *            攔截器  
    13      * @return
      
    14      */
      
    15     public <T>
     T createProxy(T target, Interceptor interceptor);   
    16 }  

    步驟2: 定義接口Interceptor

     1 package com.cyh.proxy.interceptor;   
     2 
      
     3 import
     java.lang.reflect.Method;   
     4 
      
     5 public interface
     Interceptor {   
     6     public void
     before(Method method, Object[] args);   
     7 
      
     8     public void
     after(Method method, Object[] args);   
     9 
      
    10     public void
     afterThrowing(Method method, Object[] args, Throwable throwable);   
    11 
      
    12     public void
     afterFinally(Method method, Object[] args);   
    13 
    }  
    14 

    步驟3: 實現接口DynamicProxyFactory
     1 package com.cyh.proxy.interceptor.impl;   
     2 
      
     3 import
     java.lang.reflect.InvocationHandler;   
     4 import
     java.lang.reflect.Proxy;   
     5 
      
     6 import
     com.cyh.proxy.interceptor.DynamicProxyFactory;   
     7 import
     com.cyh.proxy.interceptor.Interceptor;   
     8 
      
     9 public class DynamicProxyFactoryImpl implements
     DynamicProxyFactory {   
    10     /**
      
    11 
         * 生成動態代理,并且在調用代理執行函數的時候使用攔截器  
    12 
         *   
    13      * @param
     target  
    14 
         *  需要代理的實例  
    15      * @param
     interceptor  
    16 
         *  攔截器實現,就是我們希望代理類執行函數的前后,  
    17 
         *  拋出異常,finally的時候去做寫什么  
    18      */
      
    19 
        @Override  
    20     @SuppressWarnings("unchecked"
    )   
    21     public <T>
     T createProxy(T target, Interceptor interceptor) {   
    22     // 當前對象的類加載器   

    23     ClassLoader classLoader = target.getClass().getClassLoader();   
    24     // 獲取此對象實現的所有接口   

    25     Class<?>[] interfaces = target.getClass().getInterfaces();   
    26     // 利用DynamicProxyInvocationHandler類來實現InvocationHandler   

    27     InvocationHandler handler = new DynamicProxyInvocationHandler(target,   
    28 
            interceptor);   
    29 
      
    30     return
     (T) Proxy.newProxyInstance(classLoader, interfaces, handler);   
    31 
        }   
    32 }  

    步驟4: 實現調用處理器
     1 package com.cyh.proxy.interceptor.impl;   
     2 
      
     3 import
     java.lang.reflect.InvocationHandler;   
     4 import
     java.lang.reflect.Method;   
     5 
      
     6 import
     com.cyh.proxy.interceptor.Interceptor;   
     7 
      
     8 /**
      
     9 
     * 動態代理的調用處理器  
    10 
     *   
    11  * @author
     chen.yinghua  
    12  */
      
    13 public class DynamicProxyInvocationHandler implements
     InvocationHandler {   
    14     private
     Object target;   
    15     private
     Interceptor interceptor;   
    16 
      
    17     /**
      
    18      * @param
     target  
    19 
         *            需要代理的實例  
    20      * @param
     interceptor  
    21 
         *            攔截器  
    22      */
      
    23     public
     DynamicProxyInvocationHandler(Object target,   
    24 
                                      Interceptor interceptor) {   
    25     this.target =
     target;   
    26     this.interceptor =
     interceptor;   
    27 
        }   
    28 
      
    29     /**
      
    30      * @param
     proxy  
    31 
         *            所生成的代理對象  
    32      * @param
     method  
    33 
         *            調用的方法示例  
    34 
         * @args args 參數數組  
    35 
         * @Override  
    36      */
      
    37     public
     Object invoke(Object proxy, Method method, Object[] args)   
    38         throws
     Throwable {   
    39     Object result = null
    ;   
    40 
      
    41     try
     {   
    42         // 在執行method之前調用interceptor去做什么事   

    43         this.interceptor.before(method, args);   
    44         // 在這里我們調用原始實例的method   

    45         result = method.invoke(this.target, args);   
    46         // 在執行method之后調用interceptor去做什么事   

    47         this.interceptor.after(method, args);   
    48     } catch
     (Throwable throwable) {   
    49         // 在發生異常之后調用interceptor去做什么事   

    50         this.interceptor.afterThrowing(method, args, throwable);   
    51         throw
     throwable;   
    52     } finally
     {   
    53         // 在finally之后調用interceptor去做什么事   

    54         interceptor.afterFinally(method, args);   
    55 
        }   
    56 
      
    57     return
     result;   
    58 
        }   
    59 
      
    60 }  


    好了,目前為止,這個框架算完成了,怎么用呢?
    接下來我們完成測試包。

    完成測試

    步驟1: 首先,給需要代理的類定義一個接口Service
    1 package com.cyh.proxy.interceptor.test;   
    2 
      
    3 public interface
     Service {   
    4     public
     String greet(String name);   
    5 }  

    步驟2: 實現這個接口,編寫類ServiceImpl
     1 package com.cyh.proxy.interceptor.test;   
     2 
      
     3 public class ServiceImpl implements
     Service {   
     4 
        @Override  
     5     public
     String greet(String name) {   
     6     String result = "Hello, " +
     name;   
     7 
        System.out.println(result);   
     8     return
     result;   
     9 
        }   
    10 }  

    步驟3: 實現攔截器接口Interceptor,編寫類InterceptorImpl

     1package com.cyh.proxy.interceptor.test;   
     2
      
     3import
     java.lang.reflect.Method;   
     4
      
     5import
     com.cyh.proxy.interceptor.Interceptor;   
     6
      
     7public class InterceptorImpl implements Interceptor 
    {   
     8
        @Override  
     9    public void after(Method method, Object[] args) 
    {   
    10    System.out.println("after invoking method: " +
     method.getName());   
    11    }
       
    12
      
    13
        @Override  
    14    public void afterFinally(Method method, Object[] args) 
    {   
    15    System.out.println("afterFinally invoking method: " +
     method.getName());   
    16    }
       
    17
      
    18
        @Override  
    19    public void
     afterThrowing(Method method, Object[] args,    
    20                                Throwable throwable) 
    {   
    21    System.out.println("afterThrowing invoking method: "
      
    22                                                +
     method.getName());   
    23    }
       
    24
      
    25
        @Override  
    26    public void before(Method method, Object[] args) 
    {   
    27    System.out.println("before invoking method: " +
     method.getName());   
    28    }
       
    29}
      

    步驟4:編寫測試類TestDynamicProxy

     1 package com.cyh.proxy.interceptor.test;   
     2 
      
     3 import
     com.cyh.proxy.interceptor.DynamicProxyFactory;   
     4 import
     com.cyh.proxy.interceptor.Interceptor;   
     5 import
     com.cyh.proxy.interceptor.impl.DynamicProxyFactoryImpl;   
     6 
      
     7 public class
     TestDynamicProxy {   
     8     public
     TestDynamicProxy() {   
     9     DynamicProxyFactory dynamicProxyFactory = new
     DynamicProxyFactoryImpl();   
    10     Interceptor interceptor = new
     InterceptorImpl();   
    11     Service service = new
     ServiceImpl();   
    12 
      
    13     Service proxy =
     dynamicProxyFactory.createProxy(service, interceptor);   
    14     //
     Service proxy = DefaultProxyFactory.createProxy(service,   
    15     // interceptor);   

    16     proxy.greet("iwindyforest");   
    17 
        }   
    18 
      
    19     public static void
     main(String[] args) {   
    20     new
     TestDynamicProxy();   
    21 
        }   
    22 }  

    好了,整個測試包完成了,讓我們運行下看看運行結果:

    before invoking method: greet
    Hello, iwindyforest
    after invoking method: greet
    afterFinally invoking method: greet



    完善設計

    現在,讓我們回顧一下:接口DynamicProxyFactory,真的需要么?
    它只是一個工廠,負責生產代理的,但是我們并沒有過多的要求,因此可以說它的實現基本上是不變的。鑒于此,我們在使用createProxy()函數的時候,只需要一個靜態方法就可以了,沒有必要再初始化整個類,這樣才比較方便么。
    因此,我在com.cyh.proxy.interceptor.impl包里加了一個默認的工廠DefaultProxyFactory

     1 package com.cyh.proxy.interceptor.impl;   
     2 
      
     3 import
     java.lang.reflect.InvocationHandler;   
     4 import
     java.lang.reflect.Proxy;   
     5 
      
     6 import
     com.cyh.proxy.interceptor.Interceptor;   
     7 
      
     8 public class
     DefaultProxyFactory {   
     9     @SuppressWarnings("unchecked"
    )   
    10     public static <T>
     T createProxy(T target, Interceptor interceptor) {   
    11     // 當前對象的類加載器   

    12     ClassLoader classLoader = target.getClass().getClassLoader();   
    13     // 獲取此對象實現的所有接口   

    14     Class<?>[] interfaces = target.getClass().getInterfaces();   
    15     // 利用DynamicProxyInvocationHandler類來實現InvocationHandler   

    16     InvocationHandler handler = new DynamicProxyInvocationHandler(target,   
    17 
            interceptor);   
    18 
      
    19     return
     (T) Proxy.newProxyInstance(classLoader, interfaces, handler);   
    20 
        }   
    21 }  

    參考書籍:


    Core java Volume I
    深入淺出JDK6.0

    posted on 2009-08-15 13:16 liyang 閱讀(1654) 評論(0)  編輯  收藏 所屬分類: struts2

    主站蜘蛛池模板: 亚洲AV无码专区亚洲AV桃| a级毛片毛片免费观看久潮喷 | 又大又硬又爽免费视频| 一级一级一片免费高清| 亚洲经典在线中文字幕| 国产在线98福利播放视频免费| 一区二区视频免费观看| 亚洲另类自拍丝袜第1页| 免费一级特黄特色大片在线| 久久精品私人影院免费看| 亚洲性色精品一区二区在线| 亚洲精品午夜国产VA久久成人| 国产免费不卡视频| 一级黄色免费大片| 中文无码亚洲精品字幕| 亚洲AV无码一区二区乱孑伦AS| 日本媚薬痉挛在线观看免费| 久久福利青草精品资源站免费| 亚洲国产午夜精品理论片在线播放 | a级片免费在线播放| 亚洲性色AV日韩在线观看| 亚洲成av人影院| 免费A级毛片无码A| 99久久久国产精品免费无卡顿| 黄色网页在线免费观看| 亚洲爆乳精品无码一区二区| 77777_亚洲午夜久久多人| jlzzjlzz亚洲乱熟在线播放| 成人片黄网站色大片免费| 日韩精品无码免费一区二区三区| 羞羞漫画小舞被黄漫免费| 精品亚洲AV无码一区二区三区| 国产亚洲婷婷香蕉久久精品 | 中文字幕亚洲乱码熟女一区二区| 成年女人免费v片| 69影院毛片免费观看视频在线| 久久久受www免费人成| 国产精品亚洲精品爽爽| 国产精品亚洲综合久久| 久久精品国产亚洲av麻豆色欲| 中文字幕精品亚洲无线码一区应用|