调结者的执行action

StrutsExecuteFilter类的工作就是执行对应的action请求。StrutsExecuteFilter类的工作还需要有一个叫ExecuteOperations类的帮助。如果看过源码的朋友都知道,StrutsExecuteFilter类的代码里用了ExecuteOperations类的俩个方法。一个是:executeStaticResourceRequest方法。一个是:executeAction方法。光从字名面上我就知道他们的功能。executeStaticResourceRequest是执行静态资源请求。如JS文件,css文件等。而executeAction就是执行action请求。即是笔者想要讲的重点。好了。还是让我们先看一下StrutsExecuteFilter类代码吧。如下部分代码

StrutsExecuteFilter类:

 1 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
2
3 HttpServletRequest request = (HttpServletRequest) req;
4 HttpServletResponse response = (HttpServletResponse) res;
5
6 if (excludeUrl(request)) {//用于判断是否在排除的action之内。如果是就跳过。
7 chain.doFilter(request, response);
8 return;
9 }
10
11 if (execute == null) {
12 lazyInit();//初始化相关的信息类。
13 }
14
15 ActionMapping mapping = prepare.findActionMapping(request, response);//找到ActionMapping实例
16
17
18 Integer recursionCounter = (Integer) request.getAttribute(PrepareOperations.CLEANUP_RECURSION_COUNTER);
19
20 if (mapping == null || recursionCounter > 1) {
21 boolean handled = execute.executeStaticResourceRequest(request, response);//执行请求css,js文件。并返回是否成功。
22 if (!handled) {
23 chain.doFilter(request, response);
24 }
25 } else {
26 execute.executeAction(request, response, mapping);//执行action请求,重要部分
27 }
28 }

根据上面的红色的代码,让笔者讲一下总共做了几件事件。

1.判断当前的request请求是不是被排在外。如果就跳过去。(笔者不想过讲,太简单了)

2.判断是否存在ExecuteOperations类的实例。如果没有就初始化。相关的代码如下。

StrutsExecuteFilter类:

 1  /**
2 * 加载并初始化
3 */
4 protected synchronized void lazyInit() {
5 if (execute == null) {
6 InitOperations init = new InitOperations();//用于初始化的功能类
7 Dispatcher dispatcher = init.findDispatcherOnThread();//StrutsPrepareFilter类的时候,就把Dispatcher实例存放在本地线程里面。这是只是把他拿出来。
8 init.initStaticContentLoader(new FilterHostConfig(filterConfig), dispatcher);//初始化用于加载css,js文件的加载类。
9
10 prepare = new PrepareOperations(dispatcher);
11 execute = new ExecuteOperations(dispatcher);
12 }
13
14 }

看了代码我们就知道StrutsExecuteFilter类的lazyInit方法做了什么。

1).找到对应的Dispatcher实例。那么Dispatcher实例在哪里初始化呢?这就是StrutsPrepareFilter类的里面。(如果不理解的读者,请转至Struts2 源码分析——调结者(Dispatcher)之action请求的章节)

2).初始化StaticContentLoader类。即是用于加载JS,CSS文件等类似的加载类。

3).初始化相关对应的PrepareOperations类和ExecuteOperations类。为了下面执行action请求准备。其中ExecuteOperations类很重要。用于执行action和加载JS,CSS文件类似的调动者。

3.找到对应的action映射(ActionMapping类)。可以说没有action映射就没有办法执行相关的action操作。让我们看一下findActionMapping方法的代码吧。

PrepareOperations类:

 public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {
ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);
if (mapping == null || forceLookup) {
try {
mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());
if (mapping != null) {
request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
}
} catch (Exception ex) {
dispatcher.sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
}
} return mapping;
}

先从request请求中找到以STRUTS_ACTION_MAPPING_KEY常量为Key的ActionMapping值。如果不存在,则通过Container容器中找到的ActionMapper实例,并通过ActionMapper实例找到对应的Action映射,并存于request请求。其Key值为STRUTS_ACTION_MAPPING_KEY常量。相信读者又看Dispatcher类的实例了。又跟他有关系。关于这一步其实在StrutsPrepareFilter类工作的时候就已经做过一次了。(在这里用到ActionMapper类。关于他的作用读者目前只要知道所有的struts.xml上的配置action信息都在里面。笔者后面说找一个章节讲他)

4.如果没有找到对应的action映射(ActionMapping类)或action跳越的数量>1就是执行加载JS,CSS文件的加载类。否则就是执行action。实话实说笔者真不知道recursionCounter > 1是什么个意思。我只能把他理解为跳转的action数。笔者也做了相关通的实验就是希望看出一些事端。可惜失败了。

先看一下executeStaticResourceRequest方法吧。对于executeStaticResourceRequest方法。笔者在上面就讲到了。他是用于加载相关的静态资源。如CSS文件,JS文件。这些文件是在JAR里面的。我们有时候struts2相关的UI的TAG的时候,就要加载对应的CSS文件,和JS文件吧。这个时候他就启作用了。让我们看一下代码吧。

ExecuteOperations类:

 1     public boolean executeStaticResourceRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
2 // 如果没有找到对应的action,我们应该看一下是不是请求静态资源
3 String resourcePath = RequestUtils.getServletPath(request);
4
5 if ("".equals(resourcePath) && null != request.getPathInfo()) {
6 resourcePath = request.getPathInfo();
7 }
8
9 StaticContentLoader staticResourceLoader = dispatcher.getContainer().getInstance(StaticContentLoader.class);
10 if (staticResourceLoader.canHandle(resourcePath)) {
11 staticResourceLoader.findStaticResource(resourcePath, request, response);
12 return true;
13
14 } else {
15 // 如果不是的话,就表示他是一个普通的请求
16 return false;
17 }
18 }

因为这部分不是笔者这系列要讲的重点。如果有兴趣的读者可以自行继续研发下去。我们可以看又是跟Dispatcher类的实例有关系。相信读者这个时候很能明白笔者为什么说Dispatcher类很重要。很能做很多事情。

关于执行action的部分就在executeAction方法里面。让我们看一下代码吧。

ExecuteOperations类:

1  public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
2 dispatcher.serviceAction(request, response, mapping);
3 }

好吧。我有一种打人的冲动。Dispatcher类的实例又出现。执行request请求的action也是Dispatcher类的实例来完成的。既然如此让我们看一下代码吧。如下

 1 public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
2 throws ServletException {
3
4 Map<String, Object> extraContext = createContextMap(request, response, mapping);
5
6 //如果之前就有了值栈,就是新建一个新的值栈,放入extraContext
7 ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
8 boolean nullStack = stack == null;
9 if (nullStack) {
10 ActionContext ctx = ActionContext.getContext();
11 if (ctx != null) {
12 stack = ctx.getValueStack();
13 }
14 }
15 if (stack != null) {
16 extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
17 }
18
19 String timerKey = "Handling request from Dispatcher";
20 try {
21 UtilTimerStack.push(timerKey);
22 String namespace = mapping.getNamespace();//获得request请求里面的命名空间,即是struts.xml是的package节点元素
23 String name = mapping.getName();//获得request请求里面的action名
24 String method = mapping.getMethod();//要执行action的方法
25
26 ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name,
27 method, extraContext, true, false);//获得action的代理
28
29 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
30
31 // 如果action映射是直接就跳转到网页的话,
32 if (mapping.getResult() != null) {
33 Result result = mapping.getResult();
34 result.execute(proxy.getInvocation());
35 } else {
36 proxy.execute();//这里就是执行action
37 }
38
39
40
41 if (!nullStack) {
42 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
43 }
44 } catch (ConfigurationException e) {
45 logConfigurationException(request, e);
46 sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);
47 } catch (Exception e) {
48 if (handleException || devMode) {
49 sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
50 } else {
51 throw new ServletException(e);
52 }
53 } finally {
54 UtilTimerStack.pop(timerKey);
55 }
56 }

从上面的代码就能看出在执行action的内部还需要用到一个叫ActionProxy类。关于这部分知识,笔者其实这里不想讲的很细。主要这部分的知识太多了。但这里笔者还是希望为后面的章节做好准备。ActionProxy类可以理解他是一个代理。他的主要目地就是根据action映射得到的信息,寻找对应action类实例,然后执行对应的方法。其中包括加载对应的拦截器,初始化相应的结果。而这段代码中,在ActionProxy类的execute()方法的时候,还作了相应的判断。即是是否直接回返结果。其次还有在讲到一个关于值栈的知识。这里在获得ActionProxy类实例的时候,需要得到对应值栈的信息。但是不管如何,最后一定会把request请求的值栈重新更新一下。ValueStack(值栈)的作用相信大家都懂。我就不做过多的讲解了。

本章总结

可以说相关Dispatcher类的知识点,到本章节算是结束了。笔者把Dispatcher类的功能分为三点:一是加载struts2运行的必要条件信息;二是初始化action请求需要的信息;三是执行request请求对应的action。而关于核心机制图片的橙色部分的工作大部分笔者都有体现出来。而后面的章节都是为了这三个功能点进行的。所以希望读者能理解这三个功能。

调结者(Dispatcher)之执行action的更多相关文章

  1. Struts2 源码分析——调结者(Dispatcher)之执行action

    章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...

  2. Struts2 源码分析——调结者(Dispatcher)之action请求

    章节简言 上一章笔者讲到关于struts2启动的时候加载对应的准备工作.如加载配置文件struts.xml之类的信息.而相应的这些操作都离不开Dispatcher类的帮助.如果读者只是认为Dispat ...

  3. Struts2 源码分析——调结者(Dispatcher)之准备工作

    章节简言 上一章笔者讲到关于struts2过滤器(Filter)的知识.让我们了解到StrutsPrepareFilter和StrutsExecuteFilter的作用.特别是StrutsPrepar ...

  4. Struts2 源码分析——DefaultActionInvocation类的执行action

    本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...

  5. 在执行Action之间检验是否登录

    在执行Action之间检验是否登录,也可以在执行Action前先执行某一个操作 public class BaseController : Controller { protected string ...

  6. OCM_第十二天课程:Section6 —》数据库性能调优_ 资源管理器/执行计划

    注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...

  7. DefaultActionInvocation类的执行action

    DefaultActionInvocation类的执行action 上一章里面有提到过DefaultActionInvocation类的invoke方法里面的invokeActionOnly方法.没有 ...

  8. How to: 执行Action当收到数据时

      本文旨在演示ActionBlock的使用. 大致流程: 输入路径--读取字节--计算--传输到打印   // Demonstrates how to provide delegates to ex ...

  9. Struts2.3动态调用报 No result defined for action 错误

    struts 2.3.16  採用动态调用发现不工作报404 not found,网上查找原因: 1.由于:struts2中默认不同意使用DMI 所以:须要在配置文件里打开: <constant ...

随机推荐

  1. E492: Not an editor command: ^M

    在windows下拷贝vimrc到Linux,运行vim命令后,出现错误 vim E492: Not an editor command: ^M 原因: linux的文件换行符为\n,但windows ...

  2. js 获取当前时间并格式化

      js 获取当前时间并格式化 CreateTime--2018年2月7日11:04:16 Author:Marydon 方式一 /** * 获取系统当前时间并格式化 * @returns yyyy- ...

  3. LeetCode: Linked List Cycle [141]

    [题目] Given a linked list, determine if it has a cycle in it. Follow up: Can you solve it without usi ...

  4. gsub

    gsub("([ab])", "\\1_\\1_", "abc and ABC")[1] "a_a_b_b_c a_a_nd AB ...

  5. js操作时间 加法 减法 计算 格式化时间

    Date.prototype.Format = function (fmt) { var o = { "M+": this.getMonth() + 1, //月份 "d ...

  6. Python Kivy 安装问题解决

    Fix: Running this was suggested by @matham in #3889 and solves the problem described below:python -m ...

  7. Docker 私有仓库最简便的搭建方法

    http://blog.csdn.net/wangtaoking1/article/details/44180901/ Docker学习笔记 — Docker私有仓库搭建http://www.jian ...

  8. Laravel自定义分页样式

    <?php namespace App\Http\Controllers; use DB; use App\Http\Controllers\Controller; class UserCont ...

  9. 从12306网站新验证码看Web验证码设计与破解

    2015年3月16日,铁路官方购票网站12306又出新招,在登录界面推出了全新的验证方式,用户在填写好登录名和密码之后,还要准确的选取图片验证码才能登陆成功.据悉,12306验证码改版后,目前所有抢票 ...

  10. AngularJS ——ngResource、RESTful APIs 使用

    这篇文章里,用以下两个情景用例来解释: 保存/持久化 新的数据对象 更新存在的数据对象 代码片段包含了AngularJs代码和Spring MVC代码,以能够让你简单快速的上手. 想要$resourc ...