This website requires JavaScript.

模拟实现struts2的拦截器

拦截器是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里的内容输出了出来。

0条评论
avatar