在Struts2中有拦截器的概念,通过它的拦截器可以拦截Action。Struts2的拦截器是通过AOP来实现的,在Spring也有类似的概念。下面的我们先来比较一下Struts2和Spring中AOP的东西。
AOP概念 | Struts2 | Spring |
JoinPoint | Action中方法的执行 | 符合条件方法的执行 |
Pointcut | Action(不能自己指定) | 可以通过正则或AspectJ表达式来指定 |
Advice | Before、After、Around | Before、After、Around |
Aspect | 拦截器 | 拦截器 |
从上面的比较中可以看到,Struts2的AOP功能比较单一,只能拦截Action类中的方法。Spring的AOP是通过JDK动态代理或者CGLib来生成目标对象的代理对象,然后将增强功能(Aspect【包括了Advice和Pointcut】)织入到符合条件(Pointcut)的类的方法(JoinPoint)上。
Struts2的AOP实现跟Filter的实现差不多,它有一系列的拦截器,称为拦截器栈,通过这些拦截器栈通过ActionInvocation的调度可以在Action中方法执行之前或执行做一些操作。原理图如下:
下面,用代码来模拟一下它的实现
/** * Action、Interceptor调度器 * @author zyb * @since 2013-6-2 下午1:22:05 */ public interface ActionInvocation { String invoke(); }
/**
* Action、Interceptor调度器默认实现
* @author zyb
* @since 2013-6-2 下午1:21:14
*/
public class DefaultActionInvoation implements ActionInvocation {
private int index;
private Action action;
private List<Interceptor> interceptors = new ArrayList<Interceptor>();
public void addInterceptor(Interceptor interceptor) {
this.interceptors.add(interceptor);
}
public void setAction(Action action) {
this.action = action;
}
@Override
public String invoke() {
String result = "";
// 如果所有的拦截器已经执行完,则执行Action中的方法
if (index == interceptors.size()) {
result = action.execute();
} else {
Interceptor interceptor = interceptors.get(index);
index++;
result = interceptor.intercept(this);
}
return result;
}
}
/**
* 拦截器
* @author zyb
* @since 2013-6-2 下午1:23:35
*/
public interface Interceptor {
String intercept(ActionInvocation invocation);
}
public class ExceptionInterceptor implements Interceptor {
@Override
public String intercept(ActionInvocation invocation) {
System.out.println("ExceptionInterceptor");
return invocation.invoke();
}
}
public class I18NInterceptor implements Interceptor {
@Override
public String intercept(ActionInvocation invocation) {
System.out.println("I18NInterceptor");
return invocation.invoke();
}
}
/**
* 环绕拦截器
* @author zyb
* @since 2013-6-2 下午1:23:25
*/
public class AroundInterceptor implements Interceptor {
@Override
public String intercept(ActionInvocation invocation) {
System.out.println("before:" + this.getClass());
String result = invocation.invoke();
System.out.println("after:" + this.getClass());
return result;
}
}
/**
* 环绕拦截器
* @author zyb
* @since 2013-6-2 下午1:21:24
*/
public class AroundInterceptor01 implements Interceptor {
@Override
public String intercept(ActionInvocation invocation) {
System.out.println("before:" + this.getClass());
String result = invocation.invoke();
System.out.println("after:" + this.getClass());
return result;
}
}
/**
* Action接口
* @author zyb
* @since 2013-6-2 下午1:21:55
*/
public interface Action {
String execute();
}
public class MyAction implements Action {
@Override
public String execute() {
System.out.println("execute...");
return "success:" + getClass();
}
}
public class Test {
public static void main(String[] args) {
Interceptor exptionInterceptor = new ExceptionInterceptor();
Interceptor i18nInterceptor = new I18NInterceptor();
Interceptor aroundInterceptor = new AroundInterceptor();
Interceptor aroundInterceptor01 = new AroundInterceptor01();
DefaultActionInvoation actionInvocation = new DefaultActionInvoation();
actionInvocation.addInterceptor(exptionInterceptor);
actionInvocation.addInterceptor(i18nInterceptor);
actionInvocation.addInterceptor(aroundInterceptor);
actionInvocation.addInterceptor(aroundInterceptor01);
Action action = new MyAction();
actionInvocation.setAction(action);
String result = actionInvocation.invoke();
System.out.println("Action result:" + result);
}
}
看一下执行结果
ExceptionInterceptor
I18NInterceptor
before:class org.struts2.simulate.AroundInterceptor
before:class org.struts2.simulate.AroundInterceptor01
execute...
after:class org.struts2.simulate.AroundInterceptor01
after:class org.struts2.simulate.AroundInterceptor
Action result:success:class org.struts2.simulate.MyAction
可以看到添加进去的Interceptor像是一个栈一样,如果放进去的的Interceptor是BeforeAdvice类型的,则会在Action中的方法执行之前,执行增强操作;如果放进去的Interceptor是AroundAdvice类型的,则会在Action中的方法之前按照“进栈”的顺序执行增强操作,在Action方法执行之后,按照“出栈”的顺序执行增强操作
Struts2就是这样实现AOP的,比起Spring的AOP实现,简单多了。^_^