Struts2工作原理

转载 2016年08月28日 21:28:56

首先我们看一下struts官方给我们提供的struts执行流程

从上面流程图我们可以看出struts执行的流程大体分一下阶段:

1. 初始的请求通过一条标准的过滤器链,到达servlet 容器( 比如tomcat 容器,WebSphere 容器)。

2. 过滤器链包括可选的ActionContextCleanUp 过滤器,用于系统整合技术,如SiteMesh 插件。

3. 接着调用FilterDispatcher,FilterDispatcher 查找ActionMapper,以确定这个请求是否需要调用某个Action。

4. 如果ActionMapper 确定需要调用某个Action,FilterDispatcher 将控制权交给ActionProxy。

5. ActionProxy 依照框架的配置文件(struts.xml),找到需要调用的Action 类。

6. ActionProxy 创建一个ActionInvocation 的实例。ActionInvocation 先调用相关的拦截器(Action 调用之前的部分),最后调用Action。

7. 一旦Action 调用返回结果,ActionInvocation 根据struts.xml 配置文件,查找对应的转发路径。返回结果通常是(但不总是,也可能是另外的一个Action 链)JSP 技术或者FreeMarker的模版技术的网页呈现。Struts2 的标签和其他视图层组件,帮助呈现我们所需要的显示结果。在此,我想说清楚一些,最终的显示结果一定是HTML 标签。标签库技术和其他视图层技术只是为了动态生成HTML 标签。

8. 接着按照相反次序执行拦截器链( 执行Action 调用之后的部分)。最后,响应通过滤器链返回(过滤器技术执行流程与拦截器一样,都是先执行前面部分,后执行后面部)。如果过滤器链中存在ActionContextCleanUp,FilterDispatcher 不会清理线程局部的ActionContext。如果不存在ActionContextCleanUp 过滤器,FilterDispatcher 会清除所有线程局部变量。

下面我们就来具体分析一下3-6四个步骤:

步骤三:FilterDispatcher 查找ActionMapper,以确定这个请求是否需要调用某个Action。

1)

2调用actionmapper去寻找对应的ActionMapping因为actionmapper是一个接口,所有我们去他对应的实现类(DefaultActionMapper)里面去找getMapping方法,下面我们来看一下实现类里面的getMapping方法源代码:

                

      ActionMapping 代表struts.xml 文件中的一个Action 配置,被传入到serviceAction 中。注意ActionMapping 不代表Action 集合,只代表某个对应的Action。如果是一个Action 请求,( 请求路径在struts.xml 有对应的Action 配置,即actionmapping不为空),则调用dispatcher.serviceAction() 处理。找到对应的ActionMapping,下一步就去找具体的执行哪一个action,从FilterDispatcher源码中我们可以找到下一步流程:


    从上面可以看出,FilterDispatcher类中是调用的serviceAction方法来寻找的去调用哪一个action。serviceAction()方法作用:加载Action 类,调用Action 类的方法,转向到响应结果。响应结果指<result/> 标签所代表的对象。

步骤四、五、六:如果ActionMapper 确定需要调用某个Action,FilterDispatcher 将控制权交给ActionProxy。

我们来看一下具体的serviceAction源码:

[java] view plain copy
 print?
  1. public void serviceAction(HttpServletRequest request, HttpServletResponse response,  
  2.   
  3. ServletContext context, ActionMapping mapping) throws ServletException {  
  4.   
  5. Map<String, Object> extraContext = createContextMap  
  6.   
  7. (request, response, mapping, context);  
  8.   
  9. //1 以下代码目的为获取ValueStack,代理在调用的时候使用的是本值栈的副本  
  10.   
  11. ValueStack stack = (ValueStack) request.getAttribute  
  12.   
  13. (ServletActionContext.STRUTS_VALUESTACK_KEY);  
  14.   
  15. boolean nullStack = stack == null;  
  16.   
  17. if (nullStack) {  
  18.   
  19. ActionContext ctx = ActionContext.getContext();  
  20.   
  21. if (ctx != null) {  
  22.   
  23. stack = ctx.getValueStack();  
  24.   
  25. }  
  26.   
  27. }  
  28.   
  29. //2 创建ValueStack 的副本  
  30.   
  31. if (stack != null) {  
  32.   
  33. extraContext.put(ActionContext.VALUE_STACK,  
  34.   
  35. valueStackFactory.createValueStack(stack));  
  36.   
  37. }  
  38.   
  39. String timerKey = "Handling request from Dispatcher";  
  40.   
  41. try {  
  42.   
  43. UtilTimerStack.push(timerKey);  
  44.   
  45. //3 这个是获取配置文件中<action/> 配置的字符串,action 对象已经在核心控制器中创建  
  46.   
  47. String namespace = mapping.getNamespace();  
  48.   
  49. String name = mapping.getName();  
  50.   
  51. String method = mapping.getMethod();  
  52.   
  53. // xwork 的配置信息  
  54.   
  55. Configuration config = configurationManager.getConfiguration();  
  56.   
  57. //4 动态创建ActionProxy  
  58.   
  59. ActionProxy proxy =  
  60.   
  61. config.getContainer().getInstance(ActionProxyFactory.class).  
  62.   
  63. createActionProxy(namespace, name, method, extraContext, truefalse);  
  64.   
  65. request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY,  
  66.   
  67. proxy.getInvocation().getStack());  
  68.   
  69. //5 调用代理  
  70.   
  71. if (mapping.getResult() != null) {  
  72.   
  73. Result result = mapping.getResult();  
  74.   
  75. result.execute(proxy.getInvocation());  
  76.   
  77. else {  
  78.   
  79. proxy.execute();  
  80.   
  81. }  
  82.   
  83. //6 处理结束后,恢复值栈的代理调用前状态  
  84.   
  85. if (!nullStack) {  
  86.   
  87. request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);  
  88.   
  89. }  
  90.   
  91. catch (ConfigurationException e) {  
  92.   
  93. //7 如果action 或者result 没有找到,调用sendError 报404 错误  
  94.   
  95. }  


关于valuestack说明一下:

1.valueStack 的建立是在doFilter 的开始部分,在Action 处理之前。即使访问静态资源ValueStack 依然会建立,保存在request 作用域。

2. ValueStack 在逻辑上包含2 个部分:object stack 和context map,object stack 包含Action 与Action 相关的对象。

context map 包含各种映射关系。request,session,application,attr,parameters 都保存在context map 里。

parameters: 请求参数

atrr: 依次搜索page, request, session, 最后application 作用域。

几点说明:

1. Valuestack 对象保存在request 里,对应的key 是ServletActionContext.STRUTS_VALUESTACK_KEY。调用代理之前首先创建Valuestack 副本,调用代理时使用副本,调用后使用原实例恢复。本处的值栈指object stack。

2. Dispatcher 实例,创建一个Action 代理对象。并把处理委托给代理对象的execute 方法。

最后我们在一起看一下ActionInvocation实现类中invoke方法执行的流程:invoke源代码:

[java] view plain copy
 print?
  1.  public String invoke() throws Exception {  
  2.   
  3.         String profileKey = "invoke: ";  
  4.   
  5.         try {  
  6.   
  7.             UtilTimerStack.push(profileKey);  
  8.   
  9.             if (executed) {  
  10.   
  11.                 throw new IllegalStateException("Action has already executed");  
  12.   
  13.             }  
  14.   
  15.             if (interceptors.hasNext()) {  
  16.   
  17.                 final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();  
  18.   
  19.                 String interceptorMsg = "interceptor: " + interceptor.getName();  
  20.   
  21.                 UtilTimerStack.push(interceptorMsg);  
  22.   
  23.                 try {  
  24.   
  25.                                 resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);  
  26.   
  27.                             }  
  28.   
  29.                 finally {  
  30.   
  31.                     UtilTimerStack.pop(interceptorMsg);  
  32.   
  33.                 }  
  34.   
  35.             } else {  
  36.   
  37.                 resultCode = invokeActionOnly();  
  38.   
  39.             }  
  40.   
  41.   
  42.                if (!executed) {  
  43.   
  44.                 if (preResultListeners != null) {  
  45.   
  46.                     for (Object preResultListener : preResultListeners) {  
  47.   
  48.                         PreResultListener listener = (PreResultListener) preResultListener;  
  49.   
  50.   
  51.                         String _profileKey = "preResultListener: ";  
  52.   
  53.                         try {  
  54.   
  55.                             UtilTimerStack.push(_profileKey);  
  56.   
  57.                             listener.beforeResult(this, resultCode);  
  58.   
  59.                         }  
  60.   
  61.                         finally {  
  62.   
  63.                             UtilTimerStack.pop(_profileKey);  
  64.   
  65.                         }  
  66.   
  67.                     }  
  68.   
  69.                 }  
  70.   
  71.   
  72.                    if (proxy.getExecuteResult()) {  
  73.   
  74.                     executeResult();  
  75.   
  76.                 }  
  77.   
  78.   
  79.                 executed = true;  
  80.   
  81.             }  
  82.             return resultCode;  
  83.   
  84.         }  
  85.   
  86.         finally {  
  87.   
  88.             UtilTimerStack.pop(profileKey);  
  89.   
  90.        }  
  91. }  


        这里算是执行action中方法的最后一步了吧,至此,action的整个流程就基本差不多了,从头到尾看下来,说实话,感触很多,很多不明白的地方,这算是近了自己最大的努力去看这些源码,感觉从里面收获了很多,里面很多的机制和知识点值得我们去学习,记住了圣思源张龙老师的那句话:源码面前,一目了然

Struts2工作原理

Struts2工作原理 Struts2请求响应流程:   在struts2的应用中,从用户请求到服务器返回相应响应给用户端的过程中,包含了许多组件如:Controller、ActionProxy、Ac...
  • wuwenxiang91322
  • wuwenxiang91322
  • 2013年09月04日 16:18
  • 90847

struts2的核心和工作原理

在学习struts2之前,首先我们要明白使用struts2的目的是什么?它能给我们带来什么样的好处? 设计目标     Struts设计的第一目标就是使MVC模式应用于web程序设计。在这儿MVC模式...
  • laner0515
  • laner0515
  • 2014年05月30日 16:49
  • 352917

Struts 2详细工作流程及原理

Struts 2详细工作流程      Struts2工作原理及流程      Struts2框架的基本思想是采用MVC设计模式,即将应用设计成模型(Model)、视图(View)和控制器(Co...
  • liuyinghui523
  • liuyinghui523
  • 2015年09月08日 14:31
  • 4030

Struts2工作原理解析

struts2框架是SSH框架集中的框架之一,是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器层(Controller)来建立模...
  • u010662668
  • u010662668
  • 2017年03月16日 13:49
  • 521

Struts2工作原理以及核心思想

Struts2JAVA基础学完,肯定是要面临三大框架的学习的,作为初学者,了解三大框架的原理,设计目的是首要任务,只有在把握了框架的设计目的以后,才能有针对性的取学习使用框架,这里从strue2框架开...
  • u011958281
  • u011958281
  • 2017年07月07日 14:42
  • 1267

struts2的MVC工作原理

struts2是一种基于MVC模式的框架,M是指数据模型V 是指视图节目C 是指控制器。 客户端------控制器(FilterDispatcher)--------模型(Action)------...
  • lili72
  • lili72
  • 2012年02月22日 17:13
  • 5237

struts2 工作原理图

最近学习struts2,其实它就是webwork2.2的升级版,现附上原理图 上图来源于Struts2官方站点,是Struts 2 的整体结构。一个请求在Struts2框架中的处理大概分为以下几个步骤...
  • qjyong
  • qjyong
  • 2007年09月22日 14:31
  • 15917

Struts2工作原理详解,从Struts2的角度来理解MVC模型

1、前言         先简单说一下Struts1.x,Struts1是真正意义上的MVC模式,发布后受到广大程序开发人员的认可。性能高效、松耦合、低侵入永远是开发人员追求的理想状态,而Struts...
  • li_qinging
  • li_qinging
  • 2017年05月30日 14:18
  • 1006

漂亮回答面试官struts2的原理

众所周知,Struts2是个非常优秀的开源框架,我们能用Struts2框架进行开发,同时能快速搭建好一个Struts2框架,但我们是否能把Struts2框架的工作原理用语言表达清楚,你表达的原理不需要...
  • u011202334
  • u011202334
  • 2016年05月28日 11:01
  • 1329

Struts2的运行流程及其工作原理

Struts2是一套非常优秀的Web应用框架,实现优雅、功能强大、使用简洁。可以说是Struts2是一款非常成熟的MVC架构。 在我们学习Struts2时,最好是先学习它的运行流程、核心概念,从...
  • lijia791541916
  • lijia791541916
  • 2015年12月09日 16:42
  • 3075
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Struts2工作原理
举报原因:
原因补充:

(最多只允许输入30个字)