• Struts2源代码解读之Action调用


    对于Struts2源代码的分析已经有些时日了,虽然网上有很多解读代码,不过自己还是写一个放上来,供大家参考一下。

    解读过程:

    直接在action类中打断点(包括构造函数和待执行方法)进行debug调试,查看调用栈即可找到整个执行过程,下面用一张图来表述。

    说明一下:

    1.下面样例对应Action类为UserAction,在步骤9创建,待调用的方法为addUser

    2.因为默认拦截器比较多,下面样例只列了两个拦截器,ExceptionMappingInterceptor和DebuggingInterceptor,限于篇幅,其他的拦截器没有列出;

    3.在StrutsSpringObjectFactory到生成UserAction对象之间还有一些类的调用,同样限于篇幅,就省略了。


    下面的代码就是StrutsPrepareAndExecuteFilter的doFilter方法,有请求达到时,因为在web.xml配置了StrutsPrepareAndExecuteFilter作为过滤器,所以就会执行到doFilter方法中来,下面的调用过程大致如下:

    1.将输入参数转为HttpServletRequest和HttpServletResponse对象

    2.如果不符合过滤要求,则直接转由下一个过滤器进行处理

    3.设置字符编码和本地化信息

    4.创建Action执行上下文对象

    5.对request对象进行封装处理

    6.通过配置信息查找请求对应的actionMapping对象

    7.执行action对象对应的方法,也就是上面流程图所展示的过程

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
    
            try {
                if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
                    chain.doFilter(request, response);
                } else {
                    prepare.setEncodingAndLocale(request, response);
                    prepare.createActionContext(request, response);
                    prepare.assignDispatcherToThread();
                    request = prepare.wrapRequest(request);
                    ActionMapping mapping = prepare.findActionMapping(request, response, true);
                    if (mapping == null) {
                        boolean handled = execute.executeStaticResourceRequest(request, response);
                        if (!handled) {
                            chain.doFilter(request, response);
                        }
                    } else {
                        execute.executeAction(request, response, mapping);
                    }
                }
            } finally {
                prepare.cleanupRequest(request);
            }
        }


    在调测过程中,特别留意了ParameterInterceptor这个拦截器,没有这个拦截器,页面的参数就无法设置到Action类中去。

    看到网上有人说到自定义拦截器的时候,必须要关联defaultStack(<interceptor-ref name="defaultStack"/>),其实这没有清楚,为什么必须这样。

    defaulStack中包含很多个拦截器,其实不是所有action都需要这么多拦截器的,说实话我没有尝试过到底哪种类型的操作需要哪些拦截器,如果只是需要完成页面的值设置到action中,则只需要自定义拦截器时关联ParameterInterceptor即可,即:

    <interceptor-ref name="params">
                        <param name="excludeParams">^action:.*,^method:.*</param>

     </interceptor-ref>


    ParameterInterceptor设置值到Action中的具体代码如下:

    外部代码调用intercept方法,然后调用到doIntercept方法,将值设置到Action中则是通过下面代码中的setParameters(action, stack, parameters);这一行完成的。

    public String intercept(ActionInvocation invocation) throws Exception {
            if (applyInterceptor(invocation)) {
                return doIntercept(invocation);
            } 
            return invocation.invoke();
        }
    public String doIntercept(ActionInvocation invocation) throws Exception {
            Object action = invocation.getAction();
            if (!(action instanceof NoParameters)) {
                ActionContext ac = invocation.getInvocationContext();
                final Map<String, Object> parameters = retrieveParameters(ac);
    
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Setting params " + getParameterLogMap(parameters));
                }
    
                if (parameters != null) {
                    Map<String, Object> contextMap = ac.getContextMap();
                    try {
                        ReflectionContextState.setCreatingNullObjects(contextMap, true);
                        ReflectionContextState.setDenyMethodExecution(contextMap, true);
                        ReflectionContextState.setReportingConversionErrors(contextMap, true);
    
                        ValueStack stack = ac.getValueStack();
                        setParameters(action, stack, parameters);
                    } finally {
                        ReflectionContextState.setCreatingNullObjects(contextMap, false);
                        ReflectionContextState.setDenyMethodExecution(contextMap, false);
                        ReflectionContextState.setReportingConversionErrors(contextMap, false);
                    }
                }
            }
            return invocation.invoke();
        }


    
    
  • 相关阅读:
    [翻译]理解offsetWidth,clientWidth,scrollWidth以及Height
    [翻译]Chrome控制台API参考
    前端最新面试题
    前端面试题HTML+CSS
    css代码优化的12个技巧
    重构、标准、布局
    跨域的场景及跨域方式
    ajax
    那些我们该知道的数组操作
    全国最新行政区划省市区三级数据表(2018年9月),可直接用Python处理后导入数据库
  • 原文地址:https://www.cnblogs.com/jerry1999/p/4175929.html
Copyright © 2020-2023  润新知