Struts2中被误解的Interceptor

关于Struts2中的Interceptor,可谓是众说纷纭,五花八门,这里罗列一下网上常见的几种说法:

1、Interceptor的原理是动态代理。(尼玛,坑死人不偿命呀)

2、Interceptor的原理是责任链模式。(不要有个拦截器链就说是采用了责任链模式好不好)

3、Interceptor就是AOP。(尼玛,你了解AOP吗?)

4、Interceptor采用了AOP思想。(这个是对的)

5、Interceptor采用了AOP思想,所以它就是根据动态代理实现的。(对此我只想说,动态代理可以实现AOP,但是AOP不是动态代理,就算你知道Spring中AOP采用动态代理实现,也不要以偏概全好不好)

我说的对不对,暂不讨论,拿Struts2的源码看看不就OK了吗?

Struts2 Interceptor源码分析

Interceptor接口说明:

/* An interceptor is a stateless class that follows the interceptor pattern, as

 * found in {@link  javax.servlet.Filter} and in AOP languages.

 * Interceptors are objects that dynamically intercept Action invocations.

 * They provide the developer with the opportunity to define code that can be executed

 * before and/or after the execution of an action. They also have the ability

 * to prevent an action from executing. Interceptors provide developers a way to

 * encapulate common functionality in a re-usable form that can be applied to one or more Actions.

 * /

public interface Interceptor extends Serializable {

    /***

     * Called to let an interceptor clean up any resources it has allocated.

     */

    void destroy();

    /***

     * Called after an interceptor is created, but before any requests are processed using

     * {@link #intercept(com.opensymphony.xwork2.ActionInvocation) intercept} , giving

     * the Interceptor a chance to initialize any needed resources.

     */

    void init();

    /***

     * Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the

     * request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code.

     *

     * @param invocation the action invocation

     * @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself.

     * @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}.

     */

    String intercept(ActionInvocation invocation) throws Exception;

}

从Interceptor接口的说明中可以了解到:

1、Interceptor是一个无状态的类,它采用了拦截器模式。同样还有javax.servlet.Filter,以及AOP中的定义。(这是Interceptor的原理)

2、Interceptor是一个动态的拦截Action调用的对象,使用Interceptor可以在Action调用之前或者之后添加功能,它也可以阻止Action的执行。使用拦截器,可以定义一些通用的功能,然后用于多个Action。(这是Interceptor的功能)

接下来看看代码的结构:

找一个比较简单的拦截器实现类LoggingInterceptor:

public class LoggingInterceptor extends AbstractInterceptor {

    private static final Logger LOG = LoggerFactory.getLogger(LoggingInterceptor.class);

    private static final String FINISH_MESSAGE = "Finishing execution stack for action ";

    private static final String START_MESSAGE = "Starting execution stack for action ";

    @Override

    public String intercept(ActionInvocation invocation) throws Exception {

// 在action/interceptor调用前添加功能

        logMessage(invocation, START_MESSAGE);

// 下一个拦截器执行、或者是执行action

        String result = invocation.invoke();

// 在action/interceptor调用后添加功能

        logMessage(invocation, FINISH_MESSAGE);

        return result;

    }

    private void logMessage(ActionInvocation invocation, String baseMessage) {

        if (LOG.isInfoEnabled()) {

            StringBuilder message = new StringBuilder(baseMessage);

            String namespace = invocation.getProxy().getNamespace();

            if ((namespace != null) && (namespace.trim().length() > 0)) {

                message.append(namespace).append("/");

            }

            message.append(invocation.getProxy().getActionName());

            LOG.info(message.toString());

        }

    }

}

再来看看Struts2中ActionInvocation的默认实现:

// 只是拷贝了部分代码,因为这个类比较大

public class DefaultActionInvocation implements ActionInvocation {

    protected ActionContext invocationContext;

    protected Iterator<InterceptorMapping> interceptors;

    protected ValueStack stack; protected Result result;

    protected Result explicitResult;

    protected String resultCode;

    protected boolean executed = false;

// invoke方法

    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();

              String interceptorMsg = "interceptor: " + interceptor.getName();

              UtilTimerStack.push(interceptorMsg);

              try {

                  resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);

              }

              finally {

                  UtilTimerStack.pop(interceptorMsg);

              }

           }

           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) {

              if (preResultListeners != null) {

                  for (Object preResultListener : preResultListeners) {

                     PreResultListener listener = (PreResultListener) preResultListener;

                     String _profileKey = "preResultListener: ";

                     try {

                         UtilTimerStack.push(_profileKey);

                         listener.beforeResult(this, resultCode);

                     }

                     finally {

                         UtilTimerStack.pop(_profileKey);

                     }

                  }

              } // now execute the result, if we‘re supposed to

              if (proxy.getExecuteResult()) {

                  executeResult();

              }

              executed = true;

           }

           return resultCode;

        }

        finally {

           UtilTimerStack.pop(profileKey);

        }

     }

从 这个类中看出,从功能上确实满足了在action调用前/后附加功能的目的。调用下一个拦截器时,使用的是ActionInvocation.invoke()方法。那么接下来看看DefaultActionInvocation的设计:

把上面的DefaultActionInvocation类再简化一下就是:

public DefaultActionInvocation implements ActionInvocation{

protected Iterator<InterceptorMapping> interceptors;

public String invoke(){

if(interceptors.hasNext()){

InterceptorMapping mapping=(InterceptorMapping)interceptors.next();

Interceptor inp=mapping.getInterceptor();

String resultcode=inp.interceptor(this);

}

}

}

好了,现在为用UML类图来表示Interceptor的具体实现:

与上次模式Filter时做的类图比较一下:

对Interceptor于Filter从设计上进行比较

1、Interceptor接口就与Filter接口一样。

2、ActionInvocation接口与FilterChain接口一样。

3、FilterContext其实只是一个List<Filter>,DefaultFilterChain中包含一FilterContext,其实就是DefaultFilterChain中包含了一个List<Filter>;

DefaultActionInvocation中也包括了一个集合:Iterator<InterceptorMapping>,这样看来这个设计也是一样的。

4、在看看执行过程:

Filter执行时:

public void doFilter(request,reponse,filterChain){

filterChain.doFilter();

}

Interceptor执行时:

public String intercept(ActionInvacation invoker){

invoker.invoke();

}

5、看看如何调用:

FilterChain的实现类中:

doFilter(request, response){

Filter filter=context.getFilters.get(i);

filter.doFilter(request, response, this);

}

ActionInvocation的实现类中:

invoke(){

iterator.next().getInterceptor.invoke(this);

}

写到这个地步了,还觉得是使用的动态代理吗?还觉得是责任链模式吗?既然都把代码说到这个地步了,也就不用在模拟Interceptor了,就是Filter的翻版嘛。

既然不是动态代理,不是责任链模式,那是AOP吗?反正官方说是了。

是不是检查一下:

AOP

Advice,Pointcut, join Point, Target, Aspect;

AOP化的过程:

编译器或运行期,在Target上,找到与PointCut匹配的joinPoint,的前(或/和)后附加上advice。

把Interceptor按照AOP过程排一下:

在运行期,在Action类上,找到与**execute方法匹配的xxExecute(或者execute)方法的前面或者后面添加辅助功能。

也就是说interceptor的intercept方法中,在调用actionInvocation.invoke()的前后添加的功能就是AOP概念中的advice。

所以呢说Interceptor、Filter都是采用了AOP编程思想。并且Interceptor的作用是提供advice(附加功能)。

好吧,说到这里了,看看AOP联盟中如何定义Interceptor的:

package org.aopalliance.aop;

/**

 * Tag interface for Advice. Implementations can be any type

 * of advice, such as Interceptors.

 * @author Rod Johnson

 * @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $

 */

public interface Advice {

}

package org.aopalliance.intercept;

/**

 * This interface represents an invocation in the program.

 *

 * <p>An invocation is a joinpoint and can be intercepted by an

 * interceptor.

 *

 * @author Rod Johnson */

public interface Invocation extends Joinpoint {

   /**

    * Get the arguments as an array object.

    * It is possible to change element values within this

    * array to change the arguments.

    *

    * @return the argument of the invocation */

   Object[] getArguments();

}

至此,真相大白。

Struts2中被误解的Interceptor

时间: 2024-08-30 02:13:01

Struts2中被误解的Interceptor的相关文章

struts2中拦截器(interceptor)小结

什么是拦截器? java里的拦截器是动态拦截Action调用的对象.它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式.在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作.Struts2内置了很多拦截器,每个拦截器完成相对独立的功能,多个拦截器的组合体成为拦截器栈.最为重要的拦截器栈是

【转】Struts2的线程安全 和Struts2中的设计模式----ThreadLocal模式

[转]Struts2的线程安全 和Struts2中的设计模式----ThreadLocal模式 博客分类: 企业应用面临的问题 java并发编程 Struts2的线程安全ThreadLocal模式Struts2调用流程 转载自  http://downpour.iteye.com/blog/1335991 Struts2中的设计模式 设计模式(Design pattern)是经过程序员反复实践后形成的一套代码设计经验的总结.设计模式随着编程语言的发展,也由最初的“编程惯例”逐步发展成为被反复使用

struts2中struts.xml配置文件详解

struts.xml的常用配置 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts

struts2中的拦截器

一  AOP思想: 面向切面编程的思想 AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. AOP 是一个概念,一个规范,本身并没有设定具体语言的实现,这实际

在struts2中访问servletAPI

在struts2中访问servletAPI,通俗点也就是使用servlet中的两个对象request对象和response对象. 前几天看到一个CRM项目的源码,里面使用request对象和response对象方式和我以前使用的方式有点不同,于是便上网查询一些相关资料.特此记录于此,有兴趣的也可以参考参考. 以往使用struts2往网页填充数据通常采用往值栈存放数据,也就是ActionContext.getContext().****();后面的方法类似与request对象和response对象

Struts2中获取Web元素request、session、application对象的四种方式

我们在学习web编程的时候,一般都是通过requet.session.application(servletcontext)进行一系列相关的操作,request.session.和application他们都是web开发最常用和最实用的对象,有了它们可以大大方便开发人员进行开发和操作.但是在struts2中,基本都是action,这些个方法都是没有requet.session.application,所以如何获取这几个常用对象,也成了大家都比较关注的问题,下面我就来演示下,如何在struts2中

Struts2中获取HttpServletRequest,HttpSession等的几种方式

转自:http://www.kaifajie.cn/struts/8944.html package com.log; import java.io.IOException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import o

struts2学习笔记(6)------配置struts2中的异常处理

我们平常的异常处理是直接在方法中手动捕捉异常,当捕捉到特定异常后,返回特定逻辑视图名.这样的缺点是代码与异常处理耦合太多,一旦要改变异常处理方式,需要修改代码! struts2提供给了一种更好的方式来处理异常------声明式的方式管理异常处理,我们可以通过再方法里将出现的异常throw出去,抛给struts2框架处理,然后再struts2中默认开启着异常映射功能,该功能在struts-default.xml中配置的一个拦截器,如下: <interceptor name="exceptio

Struts2中使用execAndWait后,在 Action中调用getXXX()方法报告java.lang.NullPointerException异常的原因和解决方法

使用 Struts2 编写页面,遇到一个要长时间运行的接口,因此增加了一个execAndWait ,结果在 Action 中调用 getContext()的时候报告异常 1 ActionContext context = ActionContext.getContext(); 2 ServletContext servletContext = (ServletContext) context.get(ServletActionContext.SERVLET_CONTEXT); //抛空指针异常