随笔 - 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 阅读(1625) 评论(0)  编辑  收藏 所属分类: struts2