Struts2运行流程

来源:互联网 发布:mahout java实例教程 编辑:程序博客网 时间:2024/04/26 01:30

注:参考了其他博客,内部添加有很多自己的理解

运行流程

逐步来根据架构图进行分析(假设有一个helloWord项目)。

1:首先是在登录页面,用户填入帐号和密码,然后点击提交按钮,好了,就从这里开始分析背后的处理流程,这是我们进行分析的起点。

2:当用户提交登录请求后,请求的URL为:“/helloworld/helloworldAction.action”,请求会被Tomcat服务器接收到,Tomcat服务器会根据请求URL中的web上下文,也就是“/helloworld”,来选择处理这个请求的Web应用,那就是由helloworld这个web工程来处理这个请求。

3:Web容器会去读取helloworld这个工程的web.xml,在web.xml中进行匹配(请求先到达web.xml,这个是web应用的通用配置文件),发现后缀为“.action”的请求(不一定非要是后缀为.action,这个决定于web.xml中的配置),由struts2这个过滤器来进行处理,根据Filter的配置,找到实际的类为FilterDispatcher。(在这里过滤器可以定义多个,也可以有自定义过滤器)

4:Web容器会获取FilterDispatcher这个类的实例,然后回调doFilter方法,进行真正的处理。FilterDispatcher作为前端控制器,是整个Struts2的调度中心。

注意:在架构图上,可以看到有三个过滤器层次,分别是ActionContextCleanUp、SiteMesh等其他过滤器(特别注意,这里的其他过滤器是定义在SiteMesh和FilterDispatcher之间和FilterDispatcher。这三个层次中,ActionContextCleanUp和FilterDispatcher是Struts2的过滤器,而SiteMeshSiteMesh等其他过滤器不是(SiteMesh是一个单独的框架,不属于Struts,Struts只是集成了SiteMesh,SiteMesh应该在struts2的org.apache.struts2.dispatcher.FilterDispatcher过滤器之前 org.apache.struts2.dispatcher.ActionContextCleanUp过滤器之后,否则会有问题)。

FilterDispatcher是任何一个Struts2应用都需要配置的,一般出现在过滤器链的最后;如果在FilterDispatcher前出现了如SiteMesh这种特殊的过滤器,还必须在SiteMesh前引用Struts2的ActionContextCleanUp过滤器(这说明在返回的时候SiteMesh用到了ActionContext相关的数据)

在前面的helloworld中,并没有出现SiteMesh这种特殊的过滤器,所以只需要引用FilterDispatcher就可以了(说明ActionContextCleanUp和SiteMesh都需要手动配置)。

这就相当于前进到Struts2架构图上的第一步,(图中存在ActionContextCleanUp和SiteMesh两个过滤器并不代表在实际应用中必须存在,可灵活选择)如下所示:

图3.2  Struts2流程第一步

5:FilterDispatcher将请求转发给ActionMapper。ActionMapper负责识别当前的请求是否需要Struts2做出处理(也就是说ActionMapping的职责并不是选择执行哪个Action,仅仅是判断要不要处理这个请求,貌似还与Action本身无关,减少了不必要的判断

这就相当于前进到Struts2架构图上的第二步,如下所示:

图3.3  Struts2流程第二步

6:ActionMapper告诉FilterDispatcher(Filter在这里只是起到请求数据的初步处理并进行分发控制),需要处理这个请求,FilterDispatcher会停止过滤器链以后的部分(由此可知FilterDispatcher之后还可以定义其他过滤器,但是如果需要处理请求就会忽略之后的过滤器,那么如果不需要处理的情况下是不是会执行后续的过滤器呢???如果不会忽略,是不是就可以添加一些其他特殊的业务呢??),所以通常情况下:FilterDispatcher应该出现在过滤器链的最后。然后建立一个ActionProxy对象,这个对象作为Action与xwork之间的中间层,会代理Action的运行过程(ActionProxy向两端提供统一的接口)。

这就相当于前进到Struts2架构图上的第三步,如下所示:

图3.4  Struts2流程第三步

7:ActionProxy对象“刚被”创建出来的时候,并不知道要运行哪个Action(注意这里不知道运行哪个action,联系ActionMapping:决定要不要执行Action,它手里只有从FilterDispatcher中拿到的请求的URL。这时候,它去向ConfigurationManager询问到底要运行哪个Action(将URL交给ConfigurationManager对象,具体判断要调用那个Action由ConfigurationManager对象判断并返回,ActionProxy本身并不判断)

回忆一下,某个特定的URL由哪个Action响应由谁负责,定义在什么地方呢?没错,在struts.xml里面。而ConfigurationManager就是负责读取并管理struts.xml的,可以简单的理解为ConfigurationManager是struts.xml在内存中的映像。

在服务器启动的时候,ConfigurationManager会一次性的把struts.xml中的所有信息读到内存里,并缓存起来,以保证ActionProxy拿着来访的URL向他询问要运行哪个Action的时候,就可以直接匹配、查找并回答了。

这就相当于前进到Struts2架构图上的第四步和第五步了,如下所示:

图3.5  Struts2流程第四步和第五步

8:ActionProxy拿到了运行哪个Action、相关的拦截器以及所有可能使用的result信息(这些信息都是通过ConfigurationManager对象获得并返回的),就可以着手建立ActionInvocation对象了,ActionInvocation对象描述(或者说是定义了,当前猜想用的是Java的反射功能)了Action运行的整个过程。

Action通过configuration并根据请求的URL获取对应的action,并且获取action用到的拦截器,result,等信息,然后将这些信息传到ActionInvocation(也就是说:ActionProxy只是通过ConfigurationManager获取与请求的Action相关的信息,然后作为返回值给ActionInvocation),然后由ActionInvocation控制整个Action体系的执行。

注意:Action运行绝不仅仅只是运行Action的execute方法这么简单,还包括其他部分(在调用execute方法之前还有其他方法的调用,只要在action中定义或者说是重写了此方法,该方法就会在execute方法之前执行),完整的调用过程由ActionInvocation对象负责

这就相当于前进到Struts2架构图上的第六步,如下所示:

图3.6  Struts2流程第六步

9:回忆一下,HelloWorld中Action的execute方法运行的时候,是不是它的属性就已经有了请求中的参数呢?这说明,在execute方法之前,有人偷偷的帮我们做了这件事,把请求中的参数赋值到了Action的属性上,这个“有人”就是刚刚说的拦截器。

拦截器的运行被分成两部分,一部分在Action之前运行,一部分在Result之后运行,而且顺序是刚好反过来的。也就是在Action执行前的顺序,比如是拦截器1、拦截器2、拦截器3,那么运行Result之后,再次运行拦截器的时候,顺序就变成拦截器3、拦截器2、拦截器1了(原因:拦截器采用责任了设计模式,在单独拦截器执行的中间的某一点去调用后边的拦截器,而后边的拦截器又以同样的方式再次调用它自己后边的拦截器,直到最终的result,result执行完毕以后又会依次返回,result返回到调用它的那个拦截器,假设是第3个拦截器,此时这个拦截器调用result的那个动作执行完毕继续执行后续的代码直到结束,而结束的时候又会返回到调用它的上一个拦截器,也就是第2个拦截器,同理到第1个拦截器)。

总之ActionInvocation对象执行的时候比较复杂,会做很多事:

  • 首先按照拦截器的引用顺序依次执行各个拦截器的前置部分。

这就相当于前进到Struts2架构图上的第七步,如下所示:

图3.7  Struts2流程第七步

  • 然后执行Action的execute方法

这就相当于前进到Struts2架构图上的第八步,如下所示:

图3.8  Struts2流程第八步

  • 然后根据execute方法返回的结果,也就是Result,在struts.xml中匹配选择下一个页面

这就相当于前进到Struts2架构图上的第九步,如下所示:

图3.9  Struts2流程第九步

  • 找到页面后,由于现在的页面一般都是模板页面,在页面上,可以通过Struts2自带的标签库来访问需要的数据,并生成最终页面

这就相当于前进到Struts2架构图上的第十步,如下所示:

图3.10  Struts2流程第十步

  • 最后,ActionInvocation对象再按照拦截器的引用顺序的倒序依次执行各个拦截器的后置部分。

这就相当于前进到Struts2架构图上的第十一步,如下所示:

图3.11  Struts2流程第十一步

10:ActionInvocation对象执行完毕后,实际上就已经得到响应对象了,也就是HttpServletResponse对象,最后按与过滤器器配置定义相反的顺序依次经过过滤器,向用户展示出响应的结果。

这就相当于前进到Struts2架构图上的第十二步,得到最终完整的系统架构图了。

0 0