当用户发来的HttpRequest进入struts2框架时,struts2框架不会直接执行Action中的execute()方法,而是首先创建一个ActionInvocation的实例。
可以简单的认为ActionInvocation对象里面维护一个通过查询struct.XML 拦截器和动作得到的一个由拦截器interceptors和Action组成的对象栈。并且ActionInvocation对象维护着这个对象栈的状态。因此,它总能找到下一个拦截器或动作Action。
我们假设该ActionInvocation实例是invocation。这个实例invocation有一个发布的方法invoke()。
首先invocation.invoke()被调用,因为ActionInvocation对象维个护对象栈的状态,它总能找到下一个拦截器或者Action。第一个拦截器被找到,调用这个拦截器的intercept(ActionInvocation invocation)方法。这个方法带有一个参数invocation,这个参数指向之前所建立ActionInvocation实例invocation。拦截器方法intercept()包括了三个阶段。
1, 做一些预处理;
2, 递归调用invocation.invoke()方法将控制权交给下一个拦截器。直到Action返回字符串或拦截器自己返回字符串;
3, 做一些后加工。
如下面是一个拦截器的代码:
1, 标号1中,记录数据计入该拦截器的时间;
2, 标号2中,将控制权交给了invocation的下一个拦截器处理;
3, 标号3中,作了时间的减法运算,得出处理的时间,并写入logger。
有一些拦截器会回调后面层Action的方法,如workflow拦截器。这个拦截器作了下面的逻辑处理:
1,如果Action实现了Validateable接口,调用validate();
2,Action是否出现了错误信息(信息由validate()中的addXxxError()方法添加的),如若有,返回字符串并终止后续动作;
3,呈现于字符串匹配的JSP页面;
4,常见拦截器都放在了默认的包Struts-default的default-Stack中。
可以看到如果验证失败了,validate()直接返回了字符串,呈现页面,此时Action直接没有传达到。Workflow的拦截代码如下:
总结拦截器的递归调用时序图大致如下: