隨筆 - 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 閱讀(1658) 評論(0)  編輯  收藏 所屬分類: struts2

          主站蜘蛛池模板: 永川市| 额尔古纳市| 惠来县| 左贡县| 黄大仙区| 宁国市| 台中县| 双峰县| 边坝县| 赣榆县| 丹阳市| 开封县| 新营市| 吴堡县| 平湖市| 安丘市| 隆安县| 东阳市| 调兵山市| 宁明县| 恩施市| 牟定县| 和政县| 光山县| 从化市| 平罗县| 开原市| 电白县| 上高县| 达日县| 普兰店市| 自治县| 密云县| 获嘉县| 常宁市| 远安县| 凤山县| 安龙县| 巴青县| 道孚县| 大关县|