首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Struts2 内核之我见(4)

Struts2 内核之我见(4)

对 doFilter() 方法的几点说明 :
  • valueStack 的建立是在 doFilter 的开始部分,在 Action 处理之前。即使访问静态资源 ValueStack 依然会建立,保存在 request 作用域。
  • 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 作用域。                         图 3. 值栈
  • 准备和包装 request,包含 2 步 :
    准备请求,设置区域和字符编码
        包装 request,如果包含文件上传,则网页表单设置为 multipart/form-data,返回 MultiPartRequestWrapper 类型。
    如果普通表单提交,返回 StrutsRequestWrapper。这个类是 multipart/form-data 的父类。
  • ActionMapping 代表 struts.xml 文件中的一个 Action 配置,被传入到 serviceAction 中。注意 ActionMapping 不代表 Action 集合,只代表某个对应的 Action。                                 清单 6. action 配置
    1
    2
    3
    4
    5
    6
    <action name="Pay" class=" ">
        <interceptor-ref name="tokenSession" / >
        <interceptor-ref name="basicStack" / >
        <result name="input">/jsp/Payment.jsp</result>
        <result>/jsp/Thanks.jsp</result>
    </action>




  • 如果是一个 Action 请求,( 请求路径在 struts.xml 有对应的 Action 配置 ),则调用 dispatcher.serviceAction() 处理。
  • finally 语句块中调用 ActionContextCleanUp.cleanUp(req),以清除 ActionContext。
下边,我们将讨论 dispatcher 类。
org.apache.struts2.dispatcher.DispatcherDispatcher 做为实际派发器的工具类,委派大部分的处理任务。核心控制器持有一个本类实例,为所有的请求所共享。本部分分析了两个重要方法。
serviceAction():加载 Action 类,调用 Action 类的方法,转向到响应结果。响应结果指代码清单 5 中 <result/> 标签所代表的对象。
cleanup():释放所有绑定到 dispatcher 实例的资源。
serviceAction 方法根据 action Mapping 加载 Action 类,调用对应的 Action 方法,转向相应结果。
首先,本方法根据给定参数,创建 Action context。接着,根据 Action 的名称和命名空间,创建 Action 代理。( 注意这代理模式中的代理角色 ) 然后,调用代理的 execute() 方法,输出相应结果。
如果 Action 或者 result 没有找到,将通过 sendError() 报 404 错误。
清单 7. serviceAction 方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public void serviceAction(HttpServletRequest request, HttpServletResponse response,
          ServletContext context,  ActionMapping mapping) throws ServletException {
         Map<String, Object> extraContext = createContextMap
                     (request, response, mapping, context);

        //1 以下代码目的为获取 ValueStack,代理在调用的时候使用的是本值栈的副本
        ValueStack stack = (ValueStack) request.getAttribute
                     (ServletActionContext.STRUTS_VALUESTACK_KEY);
        boolean nullStack = stack == null;
        if (nullStack) {
            ActionContext ctx = ActionContext.getContext();
            if (ctx != null) {
                stack = ctx.getValueStack();
            }
        }
       //2 创建 ValueStack 的副本
        if (stack != null) {
            extraContext.put(ActionContext.VALUE_STACK,
                     valueStackFactory.createValueStack(stack));
        }
        String timerKey = "Handling request from Dispatcher";
        try {
            UtilTimerStack.push(timerKey);
        //3 这个是获取配置文件中 <action/> 配置的字符串,action 对象已经在核心控制器中创建
            String namespace = mapping.getNamespace();
            String name = mapping.getName();
            String method = mapping.getMethod();
            // xwork 的配置信息
            Configuration config = configurationManager.getConfiguration();

            //4 动态创建 ActionProxy
ActionProxy proxy =
config.getContainer().getInstance(ActionProxyFactory.class).
createActionProxy(namespace, name, method, extraContext, true, false);
            
            request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY,
                     proxy.getInvocation().getStack());

            
            //5 调用代理
            if (mapping.getResult() != null) {
                Result result = mapping.getResult();
                result.execute(proxy.getInvocation());
            } else {
                proxy.execute();
            }

            //6 处理结束后,恢复值栈的代理调用前状态
            if (!nullStack) {
                request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
            }
        } catch (ConfigurationException e) {
             //7 如果 action 或者 result 没有找到,调用 sendError 报 404 错误
             if(devMode) {
                 LOG.error("Could not find action or result", e);
             }
             else {
                 LOG.warn("Could not find action or result", e);
             }
            sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);
        } catch (Exception e) {
            sendError(request, response, context,
              HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
              } finally {
            UtilTimerStack.pop(timerKey);
        }
}




几点说明:
  • Valuestack 对象保存在 request 里,对应的 key 是 ServletActionContext.STRUTS_VALUESTACK_KEY。调用代理之前首先创建 Valuestack 副本,调用代理时使用副本,调用后使用原实例恢复。本处的值栈指 object stack。
  • Dispatcher 实例,创建一个 Action 代理对象。并把处理委托给代理对象的 execute 方法。
  • 如果你不懂代理模式,那么在下一部分,我会简单介绍这种模式。但本处使用的是动态代理。动态代理,指代理类和代理对象都是动态生成的,不需要编写类的源代码。
  • createContextMap 的创建,建议去看一下。代码很简单。
返回列表