拦截器(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具体类都是一个继承动态代理的类。所以这就不必为每一个类都加相应的逻辑,只需继承就行了。