1. Interceptor(拦截器)框架
Interceptor(拦截器)将Action共用的行为独立出来,在Action执行前后运行。这也就是我们所说的AOP(Aspect Oriented Programming,面向切面编程),它是分散关注的编程方法,它将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行 为发生变化,不必修改很多类,只要修改这个行为就可以。
Interceptor将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为具有很好的重用性。XWork、 WebWork的许多功能都是有Interceptor实现,可以在配置文件中组装Action用到的Interceptor,它会按照你指定的顺序,在 Action执行前后运行。Interceptor在框架中的应用如下图所示:
当你提交对Aciton(默认是.action结尾的Url)的请求时,ServletDispatcher会根据你的请求,去调度并执行相应的 Action。在Action执行之前,调用被 Interceptor截取,Interceptor在Action执行前后运行。
2. Interceptor的原理
下面我们来看看Interceptor是如何实现在Action执行前后调用的:
Action和Interceptor在框架中的执行,是由ActionInvocation对象调用的。它是用方法:String invoke() throws Exception;来实现的,它首先会依次调用Action对应的Interceptor,执行完成所有的Interceptor之后,再去调用 Action的方法,代码如下:
Interceptor interceptor = (Interceptor) interceptors.next();
resultCode = interceptor.intercept(this);
} else {
if (proxy.getConfig().getMethodName() == null) {
resultCode = getAction().execute();
} else {
resultCode = invokeAction(getAction(), proxy.getConfig());
}
}
String intercept(ActionInvocation invocation) throws Exception;。
我们一直都提到,Interceptor是在Action前后执行,可是从上面的代码我们看到的却是执行完所有Interceptor的intercept()方法之后再去调用我们的Action。“在Action前后执行”是如何实现的呢?我们来看看抽象类
public String intercept(ActionInvocation invocation) throws Exception {
String result = null;
before(invocation);
result = invocation.invoke();
after(invocation, result);
return result;
}
3. 系统Interceptor介绍
<interceptors>
<interceptor name="timer" class="com.opensymphony.xwork.interceptor.TimerInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork.interceptor.LoggingInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork.interceptor.ChainingInterceptor"/>
<interceptor name="static-params" class="com.opensymphony.xwork.interceptor.StaticParametersInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
<interceptor name="model-driven" class="com.opensymphony.xwork.interceptor.ModelDrivenInterceptor"/>
<interceptor name="component" class="com.opensymphony.xwork.interceptor.component.ComponentInterceptor"/>
<interceptor name="token" class="com.opensymphony.webwork.interceptor.TokenInterceptor"/>
<interceptor name="token-session" class="com.opensymphony.webwork.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="com.opensymphony.xwork.validator.ValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="servlet-config" class="com.opensymphony.webwork.interceptor.ServletConfigInterceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork.interceptor.PrepareInterceptor"/>
<interceptor name="conversionError" class="com.opensymphony.webwork.interceptor.WebWorkConversionErrorInterceptor"/>
<interceptor-stack name="defaultStack">
<interceptor-ref name="static-params"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
<interceptor-stack name="validationWorkflowStack">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="validation"/>
<interceptor-ref name="workflow"/>
</interceptor-stack>
</interceptors>
这些都时有框架提供的默认的Interceptor,更详细的可以参考webwork文档。
4. 自定义Interceptor
(1)创建一个自己需要的Interceptor类,它必需实现com.opensymphony.xwork.interceptor.Interceptor接口,在Interceptor的intercept方法里面完成拦截器的处理逻辑;
(2)在配置文件(xwork.xml)中申明这个Interceptor类,它放在标签<interceptor />中,同是<interceptor />标签嵌入在<interceptors />标签内部。
(3)创建Interceptor栈,使用标签:<interceptor-stack />,让一组Interceptor可以按次序调用。(可选)
(4)指定Action所要用到的Interceptor(前面申明过的),可以用<interceptor-ref />或<default-interceptor-ref />标签。前面的标签指定某个Action所用到的Interceptor,如果Action没有被用<interceptor-ref />指定Interceptor,它将使用<default-interceptor-ref />指定的Interceptor。
5. Intercepter的Unit测试
(1)首先配置Interceptor的测试环境(我理解就是模拟一个Action,通过模拟的Action启动Interceptor,模拟的Action可以不做任何的业务逻辑处理,这样就可以测试Interceptor的工作情况)
(2)测试Interceptor
附录1:拦截器代码
private static Log log = LogFactory
.getLog(SecurityInterceptor.class);
public void destroy() {
log.info(">>> 销毁拦截器");
}
public void init() {
log.info(">>> 初始化拦截器");
}
public String intercept(ActionInvocation invocation) throws Exception {
//添加拦截器处理逻辑
return "";
}
}
附录2: 配置拦截器
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.1.1//EN" "http://www.opensymphony.com/xwork/xwork-1.1.1.dtd">
<xwork>
<include file="webwork-default.xml"/>
<package name="default" extends="webwork-default">
<!-- 声明拦截器 -->
<interceptors>
<interceptor name="security" class="cn.geocoding.gb.web.filter.SecurityInterceptor"/>
</interceptors>
<action name="searchAddressElement" class="cn.geocoding.gb.web.action.datamaintain.SearchAddressElementAction">
<result name="success" type="dispatcher">/pages/datamaintain/addressElementList.jsp</result>
<!-- 拦截器 -->
<interceptor-ref name="security"/>
<interceptor-ref name="params"/>
</action>
</package>
</xwork>
private String action;
private String packageName;
/* (non-Javadoc)
* @see com.opensymphony.xwork.config.ConfigurationProvider#destroy()
*/
public void destroy() {
}
/* (non-Javadoc)
* @see com.opensymphony.xwork.config.ConfigurationProvider#
* init(com.opensymphony.xwork.config.Configuration)
*/
public void init(Configuration configurationManager)
throws ConfigurationException {
PackageConfig defaultPackageConfig = new PackageConfig();
HashMap results = new HashMap();
List<InterceptorMapping> interceptors =
new ArrayList<InterceptorMapping>();
interceptors.add(new InterceptorMapping("security",
new SecurityInterceptor()));
ActionConfig tokenActionConfig = new ActionConfig(null,
BaseMockActionTest.class, null,
results, interceptors);
defaultPackageConfig.addActionConfig(action, tokenActionConfig);
configurationManager.addPackageConfig(packageName,defaultPackageConfig);
}
/* (non-Javadoc)
* @see com.opensymphony.xwork.config.ConfigurationProvider#needsReload()
*/
public boolean needsReload() {
return false;
}
/**
* @return Returns the action.
*/
public String getAction() {
return action;
}
/**
* @param action The action to set.
*/
public void setAction(String action) {
this.action = action;
}
/**
* @return Returns the packageName.
*/
public String getPackageName() {
return packageName;
}
/**
* @param packageName The packageName to set.
*/
public void setPackageName(String packageName) {
this.packageName = packageName;
}
}
参考文献:
http://www.opensymphony.com/webwork/