1.准备阶段
注:准备阶段还有其他一些细节,比如包装Request,构建ActionContext并与当前线程绑定等,在此只挑出帮助理解流程的关键部分介绍。
准备ActionMapping
下图是StrutsPrepareAndExecuteFilter.doFilter()方法体内的部分代码
ActionMapping封装了关于目标Action的简单信息
如上图的代码所示,在prepare.findActionMapping()中,调用了ActionMapper的getActionMapping()。在该方法体内,对url进行解析,如果是一个Struts2请求,则返回一个不为null的ActionMappping。进入执行阶段。否则Struts2不受理请求。
注意的是,如果Struts2受理请求,web.xml配置的Filter链不会向下执行。所以在配置Filter时,应该保证Struts2的Filter在最后面
2.执行阶段
①创建ActionProxy
下图是DefaultActionProxyFactory.createActionProxy()方法体内的全部代码
new DefaultActionProxy()时创建的对象内只有根据ActionMapping得到的NameSpace与ActionName
②通过ConfigurationManager匹配struts.xml中对应的Action
下图是DefaultActionProxy.prepare()方法体的部分代码,即上图中的proxy.prepare()
在上图中的proxy.prepare()方法体内,先用nameSpace,action去匹配struts.xml中相对应的Action节点,并映射在ActionConfig中。
ActionConfig与ActionMapping相比,ActionConfig更加重量级,只要是配置文件中声明的都被封装在ActionConfig中。
③在ActionProxy.prepare()中初始化ActionInvocation
下图是DefaultActionProxy.prepare()方法体的部分代码,紧接上图
在DefaultActionProxy的prepare()方法中,最后调用了ActionInvocation.init(ActionProxy)方法。方法体内部分代码如下
构造Action实例,把Action压入值栈栈顶,并且初始化拦截器的集合。
小结:在初始化ActionInvocation时即调用拦截器之前把Action压入值栈。
④通过命令模式依次执行 Interceptors——>Action——>Result——>Interceptors
执行入口即ActionProxy的execute(),开启了命令。
ActionInvocation内封装了需要的Interceptors(拦截器集合),Action,Result。