java 设计模式 拦截器

来源:互联网 发布:linux执行sql文件 编辑:程序博客网 时间:2024/04/26 06:51

拦截器(interceptor)是Struts2最强大的特性之一,也可以说是struts2的核心,拦截器可以让你在Action和result被执行之前或之后进行一些处理。同时,拦截器也可以让你将通用的代码模块化并作为可重用的类。Struts2中的很多特性都是由拦截器来完成的。拦截是AOP的一种实现策略。在Webwork的中文文档的解释为:拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。谈到拦截器,还有一个词大家应该知道——拦截器链(Interceptor
Chain,在Struts 2中称为拦截器栈Interceptor
Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用

为了便于自身理解,我们自己实现一个。
在我们的请求到来之前,加入现在我进入了一个页面,而改页面是需要先检查是否已登录,此时如果我加一个判断的话,就可以很容易实现,但是当我们的页面增多时,那么就该为我们的每个请求页面都加个判断,是相当麻烦的一件事,故此,spring或struts都为我们提供了相应的拦截器,以下是拦截器的实现原理:
这里写图片描述

首先我们需要定义一个action接口

public interface Action {    String execute();}

拦截器接口

public interface Interceptor {      void before(ActionInvocation invocation);    String intercept(ActionInvocation invocation);    void after(ActionInvocation invocation);}

调度器接口

public interface ActionInvocation {    String invoke();}

定义我们的拦截器

AroundInterceptor 拦截器

package com.cmh.intercept;import com.cmh.service.ActionInvocation;public class AroundInterceptor implements Interceptor{    @Override    public void before(ActionInvocation invocation) {        // TODO Auto-generated method stub        System.out.println("before:"+"AroundInterceptor");    }    @Override    public String intercept(ActionInvocation invocation) {        // TODO Auto-generated method stub        before(invocation);        String result = invocation.invoke();        after(invocation);        return result;    }    @Override    public void after(ActionInvocation invocation) {        // TODO Auto-generated method stub        System.out.println("after:"+"AroundInterceptor");    }}

ExceptionInterceptor拦截器

package com.cmh.intercept;import com.cmh.service.ActionInvocation;public class ExceptionInterceptor implements Interceptor{    @Override    public void before(ActionInvocation invocation) {        // TODO Auto-generated method stub        System.out.println("before:"+"ExceptionInterceptor");    }    @Override    public String intercept(ActionInvocation invocation) {        // TODO Auto-generated method stub        before(invocation);        String result = invocation.invoke();        after(invocation);        return result;    }    @Override    public void after(ActionInvocation invocation) {        // TODO Auto-generated method stub        System.out.println("after:"+"ExceptionInterceptor");    }}

I18NInterceptor拦截器

package com.cmh.intercept;import com.cmh.service.ActionInvocation;public class I18NInterceptor implements Interceptor{    @Override    public void before(ActionInvocation invocation) {        // TODO Auto-generated method stub        System.out.println("before:"+"I18NInterceptor");    }    @Override    public String intercept(ActionInvocation invocation) {        // TODO Auto-generated method stub        before(invocation);        String result = invocation.invoke();        after(invocation);        return result;    }    @Override    public void after(ActionInvocation invocation) {        // TODO Auto-generated method stub        System.out.println("after:"+"I18NInterceptor");    }}

调度器实现类DefaultActionInvoation

package com.cmh.service;import java.util.ArrayList;import java.util.List;import com.cmh.action.Action;import com.cmh.intercept.Interceptor;public class DefaultActionInvoation implements ActionInvocation{    int index = 0;    private Action action;     private List<Interceptor> interceptors = new ArrayList<Interceptor>();    /**     * Get action        * @return Action the action     */    public Action getAction() {        return action;    }    /**     * Set action     * @param action Action the action to set     */    public void setAction(Action action) {        this.action = action;    }    /**     * Set interceptors     * @param interceptors List<Interceptor> the interceptors to set     */    public void addInterceptor(Interceptor interceptors) {        this.interceptors.add(interceptors);    }    @Override    public String invoke() {//递归调用        // TODO Auto-generated method stub        String result = "";         if(index == interceptors.size()){            result = action.execute();        }else{            Interceptor interceptor =interceptors.get(index);            index++;            result = interceptor.intercept(this);        }        return result;    }}

测试类

public static void test3(){        Interceptor exptionInterceptor = new ExceptionInterceptor();          Interceptor i18nInterceptor = new I18NInterceptor();          Interceptor aroundInterceptor = new AroundInterceptor();          DefaultActionInvoation actionInvocation = new DefaultActionInvoation();          actionInvocation.addInterceptor(exptionInterceptor);          actionInvocation.addInterceptor(i18nInterceptor);          actionInvocation.addInterceptor(aroundInterceptor);          Action action = new HelloWorldAction();          actionInvocation.setAction(action);          String result = actionInvocation.invoke();          System.out.println("Action result:" + result);     }

测试结果
这里写图片描述

由以上代码不难看出,当我们的请求来到时,首先会经DefaultActionInvoation 的invoke处理,调用的次序依次为
ExceptionInterceptor->I18NInterceptor->AroundInterceptor->AroundInterceptor->I18NInterceptor->ExceptionInterceptor
最后才将我们的结果给弄出来,以上为一个拦截器最基本的原理。下面我们来看看struts2中的原代码及流程

strtus2的流程图
这里写图片描述

我们再来看看他的源代码

以下是DefaultActionInvoation 中的invoke的源代码

/**  * @throws ConfigurationException If no result can be found with the returned code  */  public String invoke() throws Exception {      String profileKey = "invoke: ";      try {       UtilTimerStack.push(profileKey);       if (executed) {       throw new IllegalStateException("Action has already executed");       }          // 依次调用拦截器堆栈中的拦截器代码执行       if (interceptors.hasNext()) {       final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();       UtilTimerStack.profile("interceptor: "+interceptor.getName(),        new UtilTimerStack.ProfilingBlock<String>() {  public String doProfiling() throws Exception {                           // 将ActionInvocation作为参数,调用interceptor中的intercept方法执行       resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);       return null;  }       });       } else {       resultCode = invokeActionOnly();       }       // this is needed because the result will be executed, then control will return to the Interceptor, which will       // return above and flow through again       if (!executed) {              // 执行PreResultListener       if (preResultListeners != null) {       for (Iterator iterator = preResultListeners.iterator();       iterator.hasNext();) {       PreResultListener listener = (PreResultListener) iterator.next();       String _profileKey="preResultListener: ";       try {       UtilTimerStack.push(_profileKey);       listener.beforeResult(this, resultCode);       }       finally {       UtilTimerStack.pop(_profileKey);       }       }       }       // now execute the result, if we're supposed to              // action与interceptor执行完毕,执行Result       if (proxy.getExecuteResult()) {       executeResult();       }       executed = true;       }       return resultCode;      }      finally {       UtilTimerStack.pop(profileKey);      }  }  

拦截器的源代码

public String intercept(ActionInvocation invocation) throws Exception {  String result = null;          before(invocation);          // 调用下一个拦截器,如果拦截器不存在,则执行Action          result = invocation.invoke();          after(invocation, result);          return result;  }  

struts的拦截器最大归功于他的动态代理模式,因为我们的action具体类都是一个继承动态代理的类。所以这就不必为每一个类都加相应的逻辑,只需继承就行了。

0 0
原创粉丝点击