拦截器是struts2中不可或缺的一个功能,如模型驱动,权限管理等功能都是基于拦截器实现的。为了深入了解一下拦截器的实现原理,查看了一些资料,于是想自己也实现一下拦截器的功能来巩固一下知识。当然,这个拦截器只是一个非常简陋的拦截器,只是为了展示struts2的拦截器是怎么实现的。
首先,我们要知道,几个拦截器之间相互的关系是类似于嵌套关系,如:
public void method1(){ method2(); } public void method2(){ method3(); } public void method3(){ execute(); } public void execute(){ //执行Action中的方法 }
假如不是这种嵌套关系,而是仅仅的顺序关系,比如:
method1(); method2(); method3(); execute();
在这种情况下,我们去掉了method2,依旧能运行method3和execute方法,那这就失去了拦截器本身所想要实现的效果了。所以拦截器肯定是要像上面那样那种的嵌套关系的。
知道了拦截器之间的关系后,我们就可以实现一个拦截器管理类来注册这些拦截器
import java.lang.reflect.Method; import java.util.LinkedList; import java.util.List; public class MyInvocation { private List<Interceptor> interceptorList = new LinkedList<>();//保存拦截器对象 private Object action;//被拦截的对象 private int interceptorIndex = 0;//被拦截的调用索引 public Object getAction() { return action; } //构造方法,用于注册拦截器和Action对象 public MyInvocation(Object action, Interceptor... interceptors) { //将拦截器对象加到list中 for (int i = 0; i < interceptors.length; i++) { this.interceptorList.add(interceptors[i]); } this.action = action; } //执行调用链中的拦截器方法和execute方法 public void invoke() throws Exception { //调用链中的所有拦截器方法都执行完了,开始调用execute if (interceptorIndex == interceptorList.size()) { try { //通过反射技术在action对象中找execute方法,如果没有则抛出异常 Method method = action.getClass().getMethod("execute"); method.invoke(getAction()); } catch (Exception e) { throw new Exception("在action中没有exeute方法"); } return; } //执行调用链中的拦截器方法,并将拦截器索引+1 interceptorList.get(interceptorIndex++).interceptor(this); } }
在这个类中,通过 interceptorList
保存注册的拦截器,然后调用拦截器中的interceptor方法,所以拦截器必须要实现一个接口。
public interface Interceptor { public void interceptor(MyInvocation invocation) throws Exception; }
我们这里先写两个只有打印功能的拦截器,实现Interceptor接口
public class Interceptor2 implements Interceptor{ @Override public void interceptor(MyInvocation invocation) throws Exception { System.out.println("Interceptor2 before invoke"); invocation.invoke(); System.out.println("Interceptor2 after invoke"); } } public class Interceptor3 implements Interceptor{ @Override public void interceptor(MyInvocation invocation) throws Exception { System.out.println("Interceptor3 before invoke"); invocation.invoke(); System.out.println("Interceptor3 after invoke"); } }
在struts2中模型驱动是一个很重要的功能,这功能为我们带来很多便利,减少了很多get和set方法在Action中,模型驱动也是由拦截器的,我们这里也模拟一个模型驱动的拦截器。
public class PropertyInterceptor implements Interceptor{ @Override public void interceptor(MyInvocation invocation) throws Exception { System.out.println("PropertyInterceptor before invoke"); //获得MyAction实例 Object action=invocation.getAction(); //判断action类是否实现了Property接口 if(action instanceof Property){ Property property=(Property)action; System.out.println("property value:"+property.getValue()); } invocation.invoke();//调用下一个拦截器的invoke方法 System.out.println("PropertyInterceptor after invoke"); } }
在这个PropertyInterceptor拦截器中,我们获取了action并且判断这个action是否implement了Property这个接口,如果有,就调用action中的getValue()方法。这就相当于使用模型驱动时,action是否实现了ModelDriven接口的getModel方法一样。 接着我们就来实现Action方法,这个方法就要实现Property接口以实现“模型驱动”。并且Action方法中要用execute方法去执行我们所需要的业务代码。
public class MyAction implements Property{ @Override public String getValue() { return "属性值"; } public void execute(){ System.out.println("execute"); } }
这个Property接口很简单,就一个getValue方法这里就不写出来了。 最后我们写一个Main方法去运行一下这三个拦截器
public class Main { public static void main(String[] args) throws Exception { Interceptor2 interceptor2 = new Interceptor2(); Interceptor3 interceptor3 = new Interceptor3(); PropertyInterceptor propertyInterceptor = new PropertyInterceptor(); MyAction action = new MyAction(); MyInvocation myInvocation = new MyInvocation(action, interceptor2, interceptor3, propertyInterceptor); myInvocation.invoke(); } }
这个运行结果可以看出我们确实实现了基于嵌套的拦截器,并且模拟了模型驱动的拦截器,将getValue里的内容输出了出来。