您的位置:首页 > 其它

实现自己的拦截器框架

2012-06-27 14:21 405 查看
AOP技术是spring框架的一个重要特征。通过该特性能够在函数运行之前,之后,或者异常处理的时候执行我们需要的一些操作。

下面我们就是需要抛开AOP,Spring这样成型的框架不用,而仅仅使用java反射机制中的Proxy,InvocationHandler来实现类似Spring框架的拦截器的效果。

动态代理DynamicProxy

首先,在设计这个拦截器框架之前,我们需要明白java中动态代理是什么?我想如果早就清楚请直接跳过,如果需要了解,那我想你手边最好有一个javadoc的电子书。

Java.lang.reflect.Proxy是反射包的成员之一。具体说明请查javadoc。

用法就是比如有一个对象,我们需要在调用它提供的方法之前,干点别的什么,就不能直接调用它,而是生成一个它的代理,这个代理有这个对象所提供的所有接口方法,我们通过直接调用代理的这些方法,来实现:函数既能像原来对象的那样工作,又能在函数运行过程前后加入我们自己的处理。

这个类有个非常重要的函数用来实现某个类的代理:

1 Object java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader,

2 Class<?>[] interfaces,

3 InvocationHandler h) throws IllegalArgumentException

参数有点迷惑人,解释下:

ClassLoader 是类加载器,这个参数用来定义代理类,一般使用原对象的即可,也可以为null用上下文解决。

Class<?>[] 接口数组,就是我们需要这个代理能够提供原来的类的什么函数。如果全部则直接class.getInterfaces()来解决.

InvocationHandler 调用处理器,这个就是如果你调用代理的方法,那么这个处理器就会被关联过来,处理调用这个函数的整个过程。这个接口只定义了一个方法:

1 public Object invoke(Object proxy, Method method,

2 Object[] args) throws Throwable;

参数中proxy就是你调用的代理,method指的是你调用的代理的那个方法,args是传给该方法的参数。

我们生成某个类的代理步骤,一般需要先考虑我们在调用这个类的函数的时候(之前,或者之后)如何处理某些事情,因此我们首先考虑的就是如何实现InvocationHandler这个接口。

让我们做一个实践,做这么一个调用处理器:任何使用此处理器的代理在调用它的任何方法的时候,都打印被代理的类的类名+“.”+方法名+”(“+参数+”,”+参数+...+”)”。

步骤1: 定义接口IUser

1 package com.cyh.proxy.sample;

2

3 public 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

1 package com.cyh.proxy.interceptor.test;

2

3 import java.lang.reflect.Method;

4

5 import com.cyh.proxy.interceptor.Interceptor;

6

7 public 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 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: