实现自己的可重用拦截器机制
来源:互联网 发布:微信抽奖软件 编辑:程序博客网 时间:2024/05/22 09:42
AOP技术是spring框架的一个重要特征。通过该特性能够在函数运行之前,之后,或者异常处理的时候执行我们需要的一些操作。
下面我们就是需要抛开AOP,Spring这样成型的框架不用,而仅仅使用java反射机制中的Proxy,InvocationHandler来实现类似Spring框架的拦截器的效果。
动态代理DynamicProxy
首先,在设计这个拦截器框架之前,我们需要明白java中动态代理是什么?我想如果早就清楚请直接跳过,如果需要了解,那我想你手边最好有一个javadoc的电子书。
Java.lang.reflect.Proxy是反射包的成员之一。具体说明请查javadoc。
用法就是比如有一个对象,我们需要在调用它提供的方法之前,干点别的什么,就不能直接调用它,而是生成一个它的代理,这个代理有这个对象所提供的所有接口方法,我们通过直接调用代理的这些方法,来实现:函数既能像原来对象的那样工作,又能在函数运行过程前后加入我们自己的处理。
这个类有个非常重要的函数用来实现某个类的代理:
下面我们就是需要抛开AOP,Spring这样成型的框架不用,而仅仅使用java反射机制中的Proxy,InvocationHandler来实现类似Spring框架的拦截器的效果。
动态代理DynamicProxy
首先,在设计这个拦截器框架之前,我们需要明白java中动态代理是什么?我想如果早就清楚请直接跳过,如果需要了解,那我想你手边最好有一个javadoc的电子书。
Java.lang.reflect.Proxy是反射包的成员之一。具体说明请查javadoc。
用法就是比如有一个对象,我们需要在调用它提供的方法之前,干点别的什么,就不能直接调用它,而是生成一个它的代理,这个代理有这个对象所提供的所有接口方法,我们通过直接调用代理的这些方法,来实现:函数既能像原来对象的那样工作,又能在函数运行过程前后加入我们自己的处理。
这个类有个非常重要的函数用来实现某个类的代理:
- Object java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader,
- Class<?>[] interfaces,
- InvocationHandler h) throws IllegalArgumentException
Object java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
参数有点迷惑人,解释下:
ClassLoader 是类加载器,这个参数用来定义代理类,一般使用原对象的即可,也可以为null用上下文解决。
Class<?>[] 接口数组,就是我们需要这个代理能够提供原来的类的什么函数。如果全部则直接class.getInterfaces()来解决.
InvocationHandler 调用处理器,这个就是如果你调用代理的方法,那么这个处理器就会被关联过来,处理调用这个函数的整个过程。这个接口只定义了一个方法:
- public Object invoke(Object proxy, Method method,
- Object[] args) throws Throwable;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
参数中proxy就是你调用的代理,method指的是你调用的代理的那个方法,args是传给该方法的参数。
我们生成某个类的代理步骤,一般需要先考虑我们在调用这个类的函数的时候(之前,或者之后)如何处理某些事情,因此我们首先考虑的就是如何实现InvocationHandler这个接口。
让我们做一个实践,做这么一个调用处理器:任何使用此处理器的代理在调用它的任何方法的时候,都打印被代理的类的类名+“.”+方法名+”(“+参数+”,”+参数+...+”)”。
步骤1: 定义接口IUser
- package com.cyh.proxy.sample;
- public interface IUser {
- public String getName();
- public void setName(String name);
- }
package com.cyh.proxy.sample;public interface IUser { public String getName(); public void setName(String name);}
步骤2: 写IUser接口的实现类User
- package com.cyh.proxy.sample.impl;
- import com.cyh.proxy.sample.IUser;
- public class User implements IUser {
- String name;
- public User(String name) {
- this.name = name;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
package com.cyh.proxy.sample.impl;import com.cyh.proxy.sample.IUser;public class User implements IUser { String name; public User(String name) {this.name = name; } public String getName() {return name; } public void setName(String name) {this.name = name; }}
步骤3: 写TraceHandler实现调用处理器InvocationHandler,即在invoke()方法里我们要打印被代理的类的类名+“.”+方法名+”(“+参数+”,”+参数+...+”)”。
- package com.cyh.proxy.sample.impl;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- public class TraceHandler implements InvocationHandler {
- private Object target;
- public TraceHandler(Object target) {
- this.target = target;
- }
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- // print implicit argument
- System.out.print(target.getClass().getName());
- // print method name
- System.out.print("." + method.getName() + "(");
- // print explicit arguments
- if (args != null) {
- for (int i = 0; i < args.length; i++) {
- System.out.print(args[i]);
- if (i < args.length - 1) {
- System.out.print(",");
- }
- }
- }
- System.out.println(")");
- return method.invoke(this.target, args);
- }
- }
package com.cyh.proxy.sample.impl;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class TraceHandler implements InvocationHandler { private Object target; public TraceHandler(Object target) {this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// print implicit argumentSystem.out.print(target.getClass().getName());// print method nameSystem.out.print("." + method.getName() + "(");// print explicit argumentsif (args != null) { for (int i = 0; i < args.length; i++) {System.out.print(args[i]);if (i < args.length - 1) { System.out.print(",");} }}System.out.println(")");return method.invoke(this.target, args); }}
步骤4: 最后,让我们写测试类ProxyTest
- package com.cyh.proxy.sample.test;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- import com.cyh.proxy.sample.IUser;
- import com.cyh.proxy.sample.impl.TraceHandler;
- import com.cyh.proxy.sample.impl.User;
- public class ProxyTest {
- User user;
- public ProxyTest() {
- user = new User("LaraCroft");
- ClassLoader classLoader = user.getClass().getClassLoader();
- Class[] interfaces = user.getClass().getInterfaces();
- InvocationHandler handler = new TraceHandler(user);
- IUser proxy = (IUser) Proxy.newProxyInstance(classLoader, interfaces,
- handler);
- proxy.setName("David Beckham");
- }
- public static void main(String[] args) {
- new ProxyTest();
- }
- }
package com.cyh.proxy.sample.test;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import com.cyh.proxy.sample.IUser;import com.cyh.proxy.sample.impl.TraceHandler;import com.cyh.proxy.sample.impl.User;public class ProxyTest { User user; public ProxyTest() {user = new User("LaraCroft");ClassLoader classLoader = user.getClass().getClassLoader();Class[] interfaces = user.getClass().getInterfaces();InvocationHandler handler = new TraceHandler(user);IUser proxy = (IUser) Proxy.newProxyInstance(classLoader, interfaces,handler);proxy.setName("David Beckham"); } public static void main(String[] args) {new ProxyTest(); }}
好了,所有代码写好了,运行一下,测试结果是:
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
- package com.cyh.proxy.interceptor;
- public interface DynamicProxyFactory {
- /**
- * 生成动态代理,并且在调用代理执行函数的时候使用拦截器
- *
- * @param clazz
- * 需要实现的接口
- * @param target
- * 实现此接口的类
- * @param interceptor
- * 拦截器
- * @return
- */
- public <T> T createProxy(T target, Interceptor interceptor);
- }
package com.cyh.proxy.interceptor;public interface DynamicProxyFactory { /** * 生成动态代理,并且在调用代理执行函数的时候使用拦截器 * * @param clazz * 需要实现的接口 * @param target * 实现此接口的类 * @param interceptor * 拦截器 * @return */ public <T> T createProxy(T target, Interceptor interceptor);}
步骤2: 定义接口Interceptor
- package com.cyh.proxy.interceptor;
- import java.lang.reflect.Method;
- public interface Interceptor {
- public void before(Method method, Object[] args);
- public void after(Method method, Object[] args);
- public void afterThrowing(Method method, Object[] args, Throwable throwable);
- public void afterFinally(Method method, Object[] args);
- }
package com.cyh.proxy.interceptor;import java.lang.reflect.Method;public interface Interceptor { public void before(Method method, Object[] args); public void after(Method method, Object[] args); public void afterThrowing(Method method, Object[] args, Throwable throwable); public void afterFinally(Method method, Object[] args);}
步骤3: 实现接口DynamicProxyFactory
- package com.cyh.proxy.interceptor.impl;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- import com.cyh.proxy.interceptor.DynamicProxyFactory;
- import com.cyh.proxy.interceptor.Interceptor;
- public class DynamicProxyFactoryImpl implements DynamicProxyFactory {
- /**
- * 生成动态代理,并且在调用代理执行函数的时候使用拦截器
- *
- * @param target
- * 需要代理的实例
- * @param interceptor
- * 拦截器实现,就是我们希望代理类执行函数的前后,
- * 抛出异常,finally的时候去做写什么
- */
- @Override
- @SuppressWarnings("unchecked")
- public <T> T createProxy(T target, Interceptor interceptor) {
- // 当前对象的类加载器
- ClassLoader classLoader = target.getClass().getClassLoader();
- // 获取此对象实现的所有接口
- Class<?>[] interfaces = target.getClass().getInterfaces();
- // 利用DynamicProxyInvocationHandler类来实现InvocationHandler
- InvocationHandler handler = new DynamicProxyInvocationHandler(target,
- interceptor);
- return (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
- }
- }
package com.cyh.proxy.interceptor.impl;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import com.cyh.proxy.interceptor.DynamicProxyFactory;import com.cyh.proxy.interceptor.Interceptor;public class DynamicProxyFactoryImpl implements DynamicProxyFactory { /** * 生成动态代理,并且在调用代理执行函数的时候使用拦截器 * * @param target * 需要代理的实例 * @param interceptor * 拦截器实现,就是我们希望代理类执行函数的前后, * 抛出异常,finally的时候去做写什么 */ @Override @SuppressWarnings("unchecked") public <T> T createProxy(T target, Interceptor interceptor) {// 当前对象的类加载器ClassLoader classLoader = target.getClass().getClassLoader();// 获取此对象实现的所有接口Class<?>[] interfaces = target.getClass().getInterfaces();// 利用DynamicProxyInvocationHandler类来实现InvocationHandlerInvocationHandler handler = new DynamicProxyInvocationHandler(target,interceptor);return (T) Proxy.newProxyInstance(classLoader, interfaces, handler); }}
步骤4: 实现调用处理器
- package com.cyh.proxy.interceptor.impl;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import com.cyh.proxy.interceptor.Interceptor;
- /**
- * 动态代理的调用处理器
- *
- * @author chen.yinghua
- */
- public class DynamicProxyInvocationHandler implements InvocationHandler {
- private Object target;
- private Interceptor interceptor;
- /**
- * @param target
- * 需要代理的实例
- * @param interceptor
- * 拦截器
- */
- public DynamicProxyInvocationHandler(Object target,
- Interceptor interceptor) {
- this.target = target;
- this.interceptor = interceptor;
- }
- /**
- * @param proxy
- * 所生成的代理对象
- * @param method
- * 调用的方法示例
- * @args args 参数数组
- * @Override
- */
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object result = null;
- try {
- // 在执行method之前调用interceptor去做什么事
- this.interceptor.before(method, args);
- // 在这里我们调用原始实例的method
- result = method.invoke(this.target, args);
- // 在执行method之后调用interceptor去做什么事
- this.interceptor.after(method, args);
- } catch (Throwable throwable) {
- // 在发生异常之后调用interceptor去做什么事
- this.interceptor.afterThrowing(method, args, throwable);
- throw throwable;
- } finally {
- // 在finally之后调用interceptor去做什么事
- interceptor.afterFinally(method, args);
- }
- return result;
- }
- }
package com.cyh.proxy.interceptor.impl;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import com.cyh.proxy.interceptor.Interceptor;/** * 动态代理的调用处理器 * * @author chen.yinghua */public class DynamicProxyInvocationHandler implements InvocationHandler { private Object target; private Interceptor interceptor; /** * @param target * 需要代理的实例 * @param interceptor * 拦截器 */ public DynamicProxyInvocationHandler(Object target, Interceptor interceptor) {this.target = target;this.interceptor = interceptor; } /** * @param proxy * 所生成的代理对象 * @param method * 调用的方法示例 * @args args 参数数组 * @Override */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;try { // 在执行method之前调用interceptor去做什么事 this.interceptor.before(method, args); // 在这里我们调用原始实例的method result = method.invoke(this.target, args); // 在执行method之后调用interceptor去做什么事 this.interceptor.after(method, args);} catch (Throwable throwable) { // 在发生异常之后调用interceptor去做什么事 this.interceptor.afterThrowing(method, args, throwable); throw throwable;} finally { // 在finally之后调用interceptor去做什么事 interceptor.afterFinally(method, args);}return result; }}
好了,目前为止,这个框架算完成了,怎么用呢?
接下来我们完成测试包。
完成测试
步骤1: 首先,给需要代理的类定义一个接口Service
- package com.cyh.proxy.interceptor.test;
- public interface Service {
- public String greet(String name);
- }
package com.cyh.proxy.interceptor.test;public interface Service { public String greet(String name);}
步骤2: 实现这个接口,编写类ServiceImpl
- package com.cyh.proxy.interceptor.test;
- public class ServiceImpl implements Service {
- @Override
- public String greet(String name) {
- String result = "Hello, " + name;
- System.out.println(result);
- return result;
- }
- }
package com.cyh.proxy.interceptor.test;public class ServiceImpl implements Service { @Override public String greet(String name) {String result = "Hello, " + name;System.out.println(result);return result; }}
步骤3: 实现拦截器接口Interceptor,编写类InterceptorImpl
- package com.cyh.proxy.interceptor.test;
- import java.lang.reflect.Method;
- import com.cyh.proxy.interceptor.Interceptor;
- public class InterceptorImpl implements Interceptor {
- @Override
- public void after(Method method, Object[] args) {
- System.out.println("after invoking method: " + method.getName());
- }
- @Override
- public void afterFinally(Method method, Object[] args) {
- System.out.println("afterFinally invoking method: " + method.getName());
- }
- @Override
- public void afterThrowing(Method method, Object[] args,
- Throwable throwable) {
- System.out.println("afterThrowing invoking method: "
- + method.getName());
- }
- @Override
- public void before(Method method, Object[] args) {
- System.out.println("before invoking method: " + method.getName());
- }
- }
package com.cyh.proxy.interceptor.test;import java.lang.reflect.Method;import com.cyh.proxy.interceptor.Interceptor;public class InterceptorImpl implements Interceptor { @Override public void after(Method method, Object[] args) {System.out.println("after invoking method: " + method.getName()); } @Override public void afterFinally(Method method, Object[] args) {System.out.println("afterFinally invoking method: " + method.getName()); } @Override public void afterThrowing(Method method, Object[] args, Throwable throwable) {System.out.println("afterThrowing invoking method: " + method.getName()); } @Override public void before(Method method, Object[] args) {System.out.println("before invoking method: " + method.getName()); }}
步骤4:编写测试类TestDynamicProxy
- package com.cyh.proxy.interceptor.test;
- import com.cyh.proxy.interceptor.DynamicProxyFactory;
- import com.cyh.proxy.interceptor.Interceptor;
- import com.cyh.proxy.interceptor.impl.DynamicProxyFactoryImpl;
- public class TestDynamicProxy {
- public TestDynamicProxy() {
- DynamicProxyFactory dynamicProxyFactory = new DynamicProxyFactoryImpl();
- Interceptor interceptor = new InterceptorImpl();
- Service service = new ServiceImpl();
- Service proxy = dynamicProxyFactory.createProxy(service, interceptor);
- // Service proxy = DefaultProxyFactory.createProxy(service,
- // interceptor);
- proxy.greet("iwindyforest");
- }
- public static void main(String[] args) {
- new TestDynamicProxy();
- }
- }
package com.cyh.proxy.interceptor.test;import com.cyh.proxy.interceptor.DynamicProxyFactory;import com.cyh.proxy.interceptor.Interceptor;import com.cyh.proxy.interceptor.impl.DynamicProxyFactoryImpl;public class TestDynamicProxy { public TestDynamicProxy() {DynamicProxyFactory dynamicProxyFactory = new DynamicProxyFactoryImpl();Interceptor interceptor = new InterceptorImpl();Service service = new ServiceImpl();Service proxy = dynamicProxyFactory.createProxy(service, interceptor);// Service proxy = DefaultProxyFactory.createProxy(service,// interceptor);proxy.greet("iwindyforest"); } public static void main(String[] args) {new TestDynamicProxy(); }}
好了,整个测试包完成了,让我们运行下看看运行结果:
before invoking method: greet
Hello, iwindyforest
after invoking method: greet
afterFinally invoking method: greet
完善设计
现在,让我们回顾一下:接口DynamicProxyFactory,真的需要么?
它只是一个工厂,负责生产代理的,但是我们并没有过多的要求,因此可以说它的实现基本上是不变的。鉴于此,我们在使用createProxy()函数的时候,只需要一个静态方法就可以了,没有必要再初始化整个类,这样才比较方便么。
因此,我在com.cyh.proxy.interceptor.impl包里加了一个默认的工厂DefaultProxyFactory:
- package com.cyh.proxy.interceptor.impl;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Proxy;
- import com.cyh.proxy.interceptor.Interceptor;
- public class DefaultProxyFactory {
- @SuppressWarnings("unchecked")
- public static <T> T createProxy(T target, Interceptor interceptor) {
- // 当前对象的类加载器
- ClassLoader classLoader = target.getClass().getClassLoader();
- // 获取此对象实现的所有接口
- Class<?>[] interfaces = target.getClass().getInterfaces();
- // 利用DynamicProxyInvocationHandler类来实现InvocationHandler
- InvocationHandler handler = new DynamicProxyInvocationHandler(target,
- interceptor);
- return (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
- }
- }
package com.cyh.proxy.interceptor.impl;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import com.cyh.proxy.interceptor.Interceptor;public class DefaultProxyFactory { @SuppressWarnings("unchecked") public static <T> T createProxy(T target, Interceptor interceptor) {// 当前对象的类加载器ClassLoader classLoader = target.getClass().getClassLoader();// 获取此对象实现的所有接口Class<?>[] interfaces = target.getClass().getInterfaces();// 利用DynamicProxyInvocationHandler类来实现InvocationHandlerInvocationHandler handler = new DynamicProxyInvocationHandler(target,interceptor);return (T) Proxy.newProxyInstance(classLoader, interfaces, handler); }}
0 0
- 实现自己的可重用拦截器机制
- 实现自己的可重用拦截器机制
- iOS cell的可重用机制
- 实现动态的可重用 SOA
- 实现动态、可重用的SOA
- 设计实现可重用的 SWT 构件
- 实现自己的拦截器框架
- SpringMVC中实现自己的拦截器
- listView的可重用机制对性能的影响
- listView的可重用机制对性能的影响
- 可重用的SVG
- UISCrollView实现重用机制
- 关于事件拦截机制-自己的理解
- 根据hibernate拦截器实现可配置日志的记录
- 用C++实现可重用的数学例程
- IOS之UITableView优化-可重用机制
- UItableView的重用机制
- UITableView的重用机制
- 如何开发wince usb 摄像头的驱动 - wincemobile的专栏 - CSDNBlog
- Linux下设置Oracle自启动
- 什么是URL
- 何为“大数据时代”
- 填数字玩游戏——穷举法演示
- 实现自己的可重用拦截器机制
- SAP ABAP F4的检索帮助(包括自定义检索帮助)
- StringUtils 工具类的常用方法
- 嵌入式Linux下NFS配置和使用说明
- 基于嵌入式ARM的工控主板与X86工控主板的比较
- STL中map用法详解
- BAT 批处理脚本
- 写出兼容性好且不容易出错的CSS样式规则
- C 基础知识