相信熟悉 Struts1 的程序员,对 Struts2 会迷惑,凡事是是而非。我也曾经遇到了这种情况。Struts2 在设计的时候采用 webwork 的内核,尽量按照 Struts1 的编码习惯。
我不知道各位怎么学习 Struts1,当我阅读了核心控制器 org.apache.struts.action.ActionServlet 的源码后,感到对 Struts1 的工作机制豁然开朗。 Struts2 同样也是 MVC 框架,但核心控制器是过滤器 org.apache.struts2.dispatcher.FilterDispatcher。
感谢网上对 Struts2 工作机制研究并且愿意跟大家分享的热心人,我在学习 Struts2 的时候得到很多帮助。如果你不是很有经验的程序员,我说的很多东西你可能立刻理解不了。如果有时间,我会做成 ppt,也希望给大家讲解,共同交流进步。
如果你需要亲自动手实践,学习源码,请下载以下的 2 个 jar 包。
图 1. 官方源码包 工作流程的官方描述我们从看官方的流程图开始。当本篇文章结束的时候,我们会再一遍来看它。
图 2. 官方工作流程图
- 初始的请求通过一条标准的过滤器链,到达 servlet 容器 ( 比如 tomcat 容器,WebSphere 容器 )。
- 过滤器链包括可选的 ActionContextCleanUp 过滤器,用于系统整合技术,如 SiteMesh 插件。
- 接着调用 FilterDispatcher,FilterDispatcher 查找 ActionMapper,以确定这个请求是否需要调用某个 Action。
- 如果 ActionMapper 确定需要调用某个 Action,FilterDispatcher 将控制权交给 ActionProxy。
- ActionProxy 依照框架的配置文件(struts.xml),找到需要调用的 Action 类。
- ActionProxy 创建一个 ActionInvocation 的实例。ActionInvocation 先调用相关的拦截器 (Action 调用之前的部分),最后调用 Action。
- 一旦 Action 调用返回结果,ActionInvocation 根据 struts.xml 配置文件,查找对应的转发路径。返回结果通常是(但不总是,也可能是另外的一个 Action 链)JSP 技术或者 FreeMarker 的模版技术的网页呈现。Struts2 的标签和其他视图层组件,帮助呈现我们所需要的显示结果。在此,我想说清楚一些,最终的显示结果一定是 HTML 标签。标签库技术和其他视图层技术只是为了动态生成 HTML 标签。
- 接着按照相反次序执行拦截器链 ( 执行 Action 调用之后的部分 )。最后,响应通过滤器链返回(过滤器技术执行流程与拦截器一样,都是先执行前面部分,后执行后面部)。如果过滤器链中存在 ActionContextCleanUp,FilterDispatcher 不会清理线程局部的 ActionContext。如果不存在 ActionContextCleanUp 过滤器,FilterDispatcher 会清除所有线程局部变量。
备注:拦截和过滤器的执行顺序可能一些人理解不了,我以生活中的范例说明。我去上海的 IBM 实验室出差,火车沿途停靠蚌埠,南京,最终达到上海。办完事情后回来,沿途的停靠站是南京、蚌埠。有没有注意到火车停靠站的顺序相反了。好,转到我们遇到的技术问题,上海的业务相当于 Action 执行,是调用的真正目标。蚌埠和南京是两个分别的过滤器。即使我两次路过南京,只是一个过滤器的调用先执行一半后执行一半罢了。 |