Struts2请求处理流程及源码分析
1.1 Struts2请求处理
1. 一个请求在Struts2框架中的处理步骤:
a) 客户端初始化一个指向Servlet容器的请求;
b) 根据Web.xml配置,请求首先经过ActionContextCleanUp过滤器,其为可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助(SiteMesh Plugin),主要清理当前线程的ActionContext和Dispatcher;
c) 请求经过插件过滤器,如:SiteMesh、etc等过滤器;
d) 请求经过核心过滤器FilterDispatcher,执行doFilter方法,在该方法中,询问ActionMapper来决定这个请求是否需要调用某个Action;
e) 如果ActionMapper决定需要调用某个Action,则ActionMapper会返回一个ActionMapping实例(存储Action的配置信息),并创建ActionProxy(Action代理)对象,将请求交给代理对象继续处理;
f) ActionProxy对象根据ActionMapping和Configuration Manager询问框架的配置文件,找到需要调用的Action类;
g) ActionProxy对象创建时,会同时创建一个ActionInvocation的实例;
h) ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用;
i) 一旦Action执行完毕,ActionInvocation实例负责根据struts.xml中的配置创建并返回Result。Result通常是一个需要被表示的JSP或者FreeMarker的模版,也可能是另外的一个Action链;
j) 如果要在返回Result之前做些什么,可以实现PreResultListener接口,PreResultListener可以在Interceptor中实现,也可以在Action中实现;
k) 根据Result对象信息,生成用户响应信息response,在生成响应过程中可以使用Struts2 框架中继承的标签,在此过程中仍会再次涉及到ActionMapper;
2. Struts2请求处理示意图:

1.2 Struts2请求处理源码分析
当用户向Struts2发送请求时,FilterDispatcher的doFilter()方法自动调用,doFilter()方法处理请求过程,如下:
1. 创建值栈对象stack;
2. 创建Action上下文对象;
3. 对请求进行重新封装,此次封装根据请求内容的类型不同,返回不同的对象:
如果为multipart/form-data类型,则返回MultiPartRequestWrapper类型的对象,该对象服务于文件上传,否则返回StrutsRequestWrapper类型的对象,MultiPartRequestWrapper是StrutsRequestWrapper的子类,而这两个类都是HttpServletRequest接口的实现。
4. 通过actionMapper.getMapping()获得ActionMapping对象,Action的配置信息存储在ActionMapping对象中(Action的配置信息:Action的name、namespace和要调用的方法method)。相关代码如下图所示:

以上代码,活动图如下:

5. 如果getMapping()方法返回ActionMapping对象为null,则FilterDispatcher认为用户请求不是Action,此时FilterDispatcher会首先分析:
如果请求以/struts开头,会自动查找在web.xml文件中配置的packages初始化参数,FilterDispatcher会将packages参数值包下的文件当作静态资源处理,即直接在页面上显示文件内容。
如果用户请求的资源不是以/struts开头—可能是.jsp文件,也可能是.html文件,则通过过滤器链继续往下传送,直到到达请求的资源为止。
6. 如果getMapping()方法返回有效的ActionMapping对象,则被认为正在请求某个Action,将调用Dispatcher.serviceAction(request, response, servletContext, mapping)方法。
以上六步,相关代码如下图所示:


以上代码,活动图如下:

7. 请求进入dispatcher.serviceAction(request,response,servletContext,mapping)方法中:
a) 将相关对象信息封装为Map(如:HttpServletRequest、Http parameters、HttpServletResponse、HttpSession、ServletContext、ActionMapping等对象信息),并存入到执行上下文Map中,返回执行上下文Map对象extraMap;
b) 获取mapping对象中存储的action命名空间、name属性、method属性等信息;
c) 加载并解析Struts2配置文件,如果没有人为配置,默认按顺序加载struts-default.xml、struts-plugin.xml、struts.xml,将action配置、result配置、interceptor配置,解析并存入至config对象中,返回文件配置对象config;
d) 根据执行上下文Map、action命名空间、name属性、method属性等创建用户Action的代理对象;
e) 执行Action代理对象proxy.execute()方法,并转向结果;
以上步骤相关代码,如图所示:

8. 执行Action代理对象proxy.execute()方法,该方法的执行,其实就是调用了invocation.invoke()方法,如下图所示:

9. 执行invocation.invoke()方法,实现了截拦器的递归调用和执行Action的execute()方法,DefaultActionInvocation.invoke()方法中代码,如下图所示:

在以上代码中,并未看出拦截器的递归调用,其实是否递归调用,是由程序员来控制的,递归调用实现很简单:
a) 首先看下Interceptor接口定义:

b) 所有的截拦器必须实现intercept方法,而该方法的参数恰恰又是ActionInvocation,所以如果在intercept方法中调用invocation.invoke(),则会继续从Action的Intercepor列表中找到下一个截拦器执行,依此递归调用Intercepor;
Struts2中的日志拦截器LoggingInterceptor,如下图所示:

c) 拦截器递归调用活动图,如下所示:

10. 在invocation.invoke()方法中,执行拦截器、action并获得resultCode完毕后,则会继续执行PreResultListener集合,并生成Result对象,实现PreResultListener接口,可在返回Result之前,做些自定义处理,如图所示

在返回Result之前,通过PreResultListener实现自定义处理,常用的有两种方式:一种在Interceptor中实现,一种在Action实现,如图所示:


以上两种方式,大家可以发现都是通过匿名内部类的方式实现,其实还有一种方式就是通过在拦截器中实现PreResultListener接口,并实现方法beforeResult方法,即可。如下图所示:

11. 最后,通过生成Result完成用户响应;
以上1-11步,为Struts2处理请求的完整流程分析,其相关代码调用流程,如下图所示:

原文链接:http://my.oschina.net/xianggao/blog/75514
Struts2请求处理流程及源码分析的更多相关文章
- SpringMVC执行流程及源码分析
SpringMVC流程及源码分析 前言 学了一遍SpringMVC以后,想着做一个总结,复习一下.复习写下面的总结的时候才发现,其实自己学的并不彻底.牢固.也没有学全,视频跟书本是要结合起来一起, ...
- django Rest Framework----APIView 执行流程 APIView 源码分析
在django—CBV源码分析中,我们是分析的from django.views import View下的执行流程,这篇博客我们介绍django Rest Framework下的APIView的源码 ...
- Android应用层View绘制流程与源码分析
1 背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...
- SpringMvc请求处理流程与源码探秘
流程梳理 dispatcherServlet作为前端控制器的主要作用就是接受请求与处理响应. 不过它不是传统意义上的servlet,它在接受到请求后采用转发的方式,将具体工作交给专业人士去做. 参与角 ...
- django 的请求处理部分----WSGIHandler 源码分析 django1.5.5
从这里拉开django框架的帷幕..撕开,哈哈 主要涉及的类:django.core.handlers.base.BaseHandler,django.core.handlers.wsgi.WSGIH ...
- 7.Struts2拦截器及源码分析
1.Struts2架构图 2.Struts2 执行过程分析 1.首先,因为使用 struts2 框架,请求被Struts2Filter 拦截 2.Struts2Filter 调用 DisPatche ...
- openstack cinder-backup流程与源码分析
在现在的云计算大数据环境下,备份容灾已经变成了一个炙手可热的话题,今天,和大家一起分享一下openstack是怎么做灾备的. [首先介绍快照] snapshot可以为volume创建快照,快照中保存了 ...
- Django 基于类的视图(CBV)执行流程 CBV 源码分析
一.CBV(基于类的视图) 视图是可以调用的,它接受请求并返回响应,这不仅仅是一个函数,Django提供了一些可以用作视图的类的例子,这些允许您通过继承或mixin来构建视图并重用代码. 基本示例 D ...
- Yarn任务提交流程(源码分析)
关键词:yarn rm mapreduce 提交 Based on Hadoop 2.7.1 JobSubmitter addMRFrameworkToDistributedCache(Configu ...
随机推荐
- HDU 献给杭电五十周年校庆的礼物 1290 递推
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1290 题目大意: n刀最多可以把一块蛋糕切多少块 题目分析: 假如我们按照立体考虑的话,这题就非常不 ...
- Delphi TcxTreeList 怎们显示下拉列表
TcxTreeList 怎们显示下拉列表, 操作如下: 1.定义一个TStringlist中存储你的信息. 2.然后选定在TcxTreeList的哪个列要变成TCombobox, 如下图: 3. ...
- HDOJ(HDU) 1985 Conversions(汇率转换)
Problem Description Conversion between the metric and English measurement systems is relatively simp ...
- git bash中避免在push时反复输入用户名和密码
我用的是windows系统,这几天学着使用git时发现每次使用git push时每次都要输入一遍用户名和密码,感觉特烦,特意上网查了下,找到了简化方法.虽然不是原创,但至少算是加了点自己的心得和经验吧 ...
- [Java Concurrent] 并发访问共享资源的简单案例
EvenGenerator 是一个偶数生成器,每调用一个 next() 就会加 2 并返回叠加后结果.在本案例中,充当被共享的资源. EvenChecker 实现了 Runnable 接口,可以启动新 ...
- ubuntu14.04.2 添加ppa remastersys源 镜像ubuntu系统
- L - Kakuro Extension - HDU 3338 - (最大流)
题意:有一个填数字的游戏,需要你为白色的块内填一些值,不过不能随意填的,是有一些规则的(废话),在空白的上方和作方给出一些值,如果左下角有值说明下面列的和等于这个值,右上角的值等于这行后面的数的和,如 ...
- Linux操作系统Centos7.2版本搭建Apache+PHP+Mysql环境
对于在校大学生来说腾讯云1元主机很划算,所以就申请了一台,打算在上面学习下linux,使用版本为centos7.2版本.在服务器上比较推荐centos,此版本生命周期较长,而且网上有关centos的教 ...
- homebrew介绍
对于一个习惯了在 Ubuntu 的终端上通过 apt-get 来安装工具软件的我来说,也希望在Mac上找到类似的工具,能很方便的一条命令就能安装所需的软件,而不用手工的去查找下载编译,或者是折腾安装所 ...
- Linux系统下查看某文件修改的时间戳
Linux系统下查看某文件修改的时间戳查看文件时间戳命令:stat awk.txt File: `awk.txt' Size: 20 Blocks: 8 I ...