1)前提条件html
在讲解流程以前,假设咱们已经创建了的一个名为strutsDeepen的web工程,该工程仅仅实现了简单的用户登录与欢迎界面。具体的实现为:前端
- 在web.xml中配置了Struts2的过滤器
- 写了一个Action类,名称为loginAction
- 在struts.xml中配置了这个Action类
- 写了两个页面,一个是登陆页面,一个是欢迎页面
只作了这么点事情,就能够在Struts2的帮助下顺利完成功能调用,那么Struts2内部是怎么运行的呢?逐步来根据系统架构图进行分析。web
2)运行流程缓存
- 当用户提交登陆请求后,请求的URL为:“/strutsDeepen/loginAction.action”,请求会被Tomcat服务器接收到,Tomcat服务器会根据请求URL中的web上下文,也就是“/strutsDeepen”,来选择处理这个请求的Web应用,那就是由strutsDeepen这个web工程来处理这个请求。
- Web容器会去读取strutsDeepen这个工程的web.xml,在web.xml中进行匹配,发现后缀为“.action”的请求,由struts2这个过滤器来进行处理,根据Filter的配置,找到实际的类为FilterDispatcher。
-
Web容器会获取FilterDispatcher这个类的实例,而后回调doFilter方法,进行真正的处理。FilterDispatcher做为前端控制器,是整个Struts2的调度中心。服务器
注意:在架构图上,能够看到有三个过滤器层次,分别是ActionContextCleanUp、SiteMesh等其余过滤器和FilterDispatcher。这三个层次中,ActionContextCleanUp和FilterDispatcher是Struts2的过滤器,而SiteMeshSiteMesh等其余过滤器不是。架构
FilterDispatcher是任何一个Struts2应用都须要配置的,通常出如今过滤器链的最后;若是在FilterDispatcher前出现了如SiteMesh这种特殊的过滤器,还必须在SiteMesh前引用Struts2的ActionContextCleanUp过滤器。app
在前面的strutsDeepen中,并无出现SiteMesh这种特殊的过滤器,因此只须要引用FilterDispatcher就能够了。spa
- FilterDispatcher将请求转发给ActionMapper。ActionMapper负责识别当前的请求是否须要Struts2作出处理。
- ActionMapper告诉FilterDispatcher,须要处理这个请求,FilterDispatcher会中止过滤器链之后的部分,因此一般状况下:FilterDispatcher应该出如今过滤器链的最后。而后创建一个ActionProxy对象,这个对象做为Action与xwork之间的中间层,会代理Action的运行过程。
- ActionProxy对象刚被建立出来的时候,并不知道要运行哪一个Action,它手里只有从FilterDispatcher中拿到的请求的URL。这时候,它去向ConfigurationManager询问到底要运行哪一个Action。某个特定的URL由哪一个Action响应由谁负责,定义在什么地方呢?没错,在struts.xml里面。而ConfigurationManager就是负责读取并管理struts.xml的,能够简单的理解为ConfigurationManager是struts.xml在内存中的映像。在服务器启动的时候,ConfigurationManager会一次性的把struts.xml中的全部信息读到内存里,并缓存起来,以保证ActionProxy拿着来访的URL向他询问要运行哪一个Action的时候,就能够直接匹配、查找并回答了。
-
ActionProxy拿到了运行哪一个Action、相关的拦截器以及全部可能使用的result信息,就能够着手创建ActionInvocation对象了,ActionInvocation对象描述了Action运行的整个过程。代理
注意:Action运行毫不仅仅只是运行Action的execute方法这么简单,还包括其余部分,完整的调用过程由ActionInvocation对象负责。xml
- 回忆一下,strutsDeepen中Action的execute方法运行的时候,是否是它的属性就已经有了请求中的参数呢?这说明,在execute方法以前,有人偷偷的帮咱们作了这件事,把请求中的参数赋值到了Action的属性上,这个“有人”就是刚刚说的拦截器。拦截器的运行被分红两部分,一部分在Action以前运行,一部分在Result以后运行,并且顺序是恰好反过来的。也就是在Action执行前的顺序,好比是拦截器一、拦截器二、拦截器3,那么运行Result以后,再次运行拦截器的时候,顺序就变成拦截器三、拦截器二、拦截器1了。
总之ActionInvocation对象执行的时候比较复杂,会作不少事:
- 首先,按照拦截器的引用顺序依次执行各个拦截器的前置部分;
- 而后,执行Action的execute方法;
- 而后,根据execute方法返回的结果,也就是Result,在struts.xml中匹配选择下一个页面;
- 找到页面后,因为如今的页面通常都是模板页面,在页面上,能够经过Struts2自带的标签库来访问须要的数据,并生成最终页面;
- 最后,ActionInvocation对象再按照拦截器的引用顺序的倒序依次执行各个拦截器的后置部分。
- ActionInvocation对象执行完毕后,实际上就已经获得响应对象了,也就是HttpServletResponse对象,最后按与过滤器器配置定义相反的顺序依次通过过滤器,向用户展现出响应的结果。
参考资料:http://www.iteye.com/topic/1124526