在了解 Struts2 中拦截器使用方式之前,笔者需要先向读者展示拦截器的底层实现原理是如何的。之前也说了拦截器是一个普通的 Java 对象,而被拦截的正常执行业务逻辑功能的类也是一个普通的 Java 对象,那么如何使这两个对象进行关联,并且如何知道这两个对象执行的先后顺序。
技术要点
本节代码向读者演示拦截器如何实现,介绍的知识点如下:
=??? 拦截器类和被拦截类内容。
=??? 运用反射机制调用类和类方法。
=??? 设置拦截器处理类,配置拦截器在何时执行以及拦截器类和被拦截类执行先后顺序。
=??? 设置代理对象类实现拦截器拦截功能。
=??? 测试程序运行结果显示拦截功能正常执行情况
演示代码
功能执行类:
<!------------------------------------------- 文件名: ExecuteFunction.java-------------------------------->
// 执行功能类
public ? class ExecuteFunction implements ExecuteFunctionInterface {
// 执行功能类执行方法
public void execute() {
?????????? System.out .println("execute something...");
}
}
功能执行接口:
<!--------------------------- 文件名: ExecuteFunctionInterface.java----------------->
// 执行功能接口
public ? interface ExecuteFunctionInterface {
public void execute();
}
拦截器类:
<!------------------------------------- 文件名: Interceptor.java-------------------------------->
// 拦截器类
public ? class Interceptor {
// 拦截执行功能类之前执行方法
public void beforeDoing(){
?????????? System.out .println("before doing Something...");
}
// 拦截执行功能类之后执行方法
public void afterDoing(){
?????????? System.out .println("after doing Something...");
}
}
拦截器处理类:
<!------------------------------------- 文件名: InterceptorHandler.java-------------------------------->
import ? java.lang.reflect.InvocationHandler;
import ? java.lang.reflect.Method;
// 拦截器处理类
public ? class InterceptorHandler implements InvocationHandler {
private Object object;
?
private Interceptor inter = new Interceptor();
?
// 设置需要拦截的执行功能类
public void setObject(Object object) {
?????????? this.object = object;
}
?
// 接口 invoke 方法, proxy 是代理实例, method 是实例方法, args 是代理类传入的方法参数。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
?????????? inter.beforeDoing();
??????????
?????????? //object 提供该方法的类实例, args 是调用方法所需的参数值的数组
?????????? Object returnObject = method.invoke(object, args);
?????????? inter.afterDoing();
?????????? return returnObject;
}
}
代理对象类:
<!------------------------------------- 文件名: ProxyObject.java-------------------------------->
import ? java.lang.reflect.Proxy;
?
public ? class ProxyObject {
private InterceptorHandler handler = new InterceptorHandler();
?
// 得到执行类的代理对象实例
public Object getProxy(Object object) {
?????????? handler.setObject(object);
?????????? // 创建对象实例
?????????? return Proxy.newProxyInstance (
ExecuteFunction.class.getClassLoader(),
object.getClass().getInterfaces(),
handler);
}
}
测试程序:
<!------------------------------------- 文件名: TestInterceptor.java-------------------------------->
// 测试执行类和拦截器类是否执行
public ? class TestInterceptor {
public static void main(String[] args) {
?????????? ExecuteFunctionInterface test = new ExecuteFunction();
?
?????????? // 得到执行类的一个代理对象实例
?????????? ExecuteFunctionInterface resultObject = (ExecuteFunctionInterface) new ProxyObject()
???????????????????????????? .getProxy(test);
?????????? // 代理对象执行
?????????? resultObject.execute();
}
}
右击 TestInterceptor.java 文件,然后单击 Run As|Java Aplication 属性。在 MyEclipse 控制台中显示代码中定义的打印方法。测试程序运行效果图如图 4.1 所示。
图 4.1?? 拦截器运行示例效果图
代码解释
( 1 ) ExecuteFunction 是一个正常执行业务逻辑类的 Java 类,它是继承 接口 ExecuteFunctionInterface ,其中的 execute 方法,作为示例,笔者只是调用打印方法打印了“ execute something… ”。这一行字。笔者还定义了 Interceptor 拦截器类,该类中有两个方法。也是为了示例,这两个方法都是简单打印了一行字。如图 4.2 ,如果其中 beforeDoing 方法在 ExecuteFunction 类的 execute 方法打印“ execute something… ”之前打印“ before doing Something… ”, afterDoing 方法在其后打印“ after doing Something ”就达到了拦截器在功能执行类前后执行拦截的目的。
( 2 )为了让拦截器类和被拦截的功能执行类发生关联关系,使用 Java 中的反射机制。在 InterceptorHandler 类中,通过扩展 java.lang.reflect.InvocationHandler 接口,覆盖重写invoke 方法,该方法里用method.invoke 来调用通过setObject 方法传入的功能执行类对象的方法。比如在这里通过setObject 方法传入的是ExecuteFunction 对象,该对象中包含一个execute 方法,而且是无参的,因此method.invoke 调用的就是execute 方法,只是执行了一遍打印出“execute something... ”,同时将已经被设置为私有类变量的拦截器类中的两个方法在其前后执行。其实这样invoke 方法已经将拦截器类中的两个方法在功能执行类的方法执行前后执行了,现在要做的只是如何让该类中的invoke 方法被测试程序调用。
( 3 )创建 ProxyObject 对象是想通过使用设计模式中的代理模式(由于本书不是专门介绍设计模式,请读者翻阅设计模式有关资料)来生成功能执行类的一个代理对象实例。通过 newProxyInstance 方法调用 InterceptorHandler 类。说的再明白点就是如果这个代理对象也执行 功能执行类的 execute 方法时候, newProxyInstance 方法作用是把 execute 方法指派给 InterceptorHandler 类执行,通过反射, InterceptorHandler 类执行 execute 方法是在 invoke 方法中执行,因此在 method.invoke 方法前后的拦截器类的beforeDoing 和afterDoing 方法也会执行。 从而就会按照图 4.2 顺序打印三个方法的显示内容。
注意:代理模式的定义:包装一个对象,并控制它的访问。在这里就是包装了 ExecuteFunction 对象,并控制它的 execute 方法,让它做了额外的事情就是执行拦截器类的 beforeDoing 和afterDoing 方法。
( 4 )测试程序通过新建一个代理对象类,并调用 getProxy 方法得到 ExecuteFunction 的一个代理对象实例,然后在这个代理对象执行 execute 方法时候,因为在之前已经说明其实创建代理对象实例时候,已经是调用了 InterceptorHandler 类的invoke 方法。就实现了动态代理机制(所谓动态代理就是指代理对象是代码执行时候创建的。仔细看测试程序就知道在 getProxy 方法执行前,只是新建了 ExecuteFunctionInterface 接口对象,并没有创建代理对象,这里创建代理对象目的就是让 execute 方法执行 拦截器类的方法),让拦截器类的方法也被执行了,并且执行顺序也是根据InterceptorHandler 类的invoke 方法中定义的顺序执行。拦截器相当于在功能执行类前后都拦截了它,并执行了自己的方法。
更多信息请查看?java进阶网?http://www.javady.com/index.php/category/thread