首页 > 代码库 > Struts2中被误解的Interceptor
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(); }
至此,真相大白。