struts2源码学习(三)——执行预处理

之前我们已经学习过了struts2中的初始化,对应着就是strutsprepareandexecutefilter中的init方

法,strutsprepareandexecutefilter源码如下:

public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
    protected PrepareOperations prepare;
    protected ExecuteOperations execute;
    protected List<Pattern> excludedPatterns = null;

    public void init(FilterConfig filterConfig) throws ServletException {
        InitOperations init = new InitOperations();
        Dispatcher dispatcher = null;
        try {
            FilterHostConfig config = new FilterHostConfig(filterConfig);
            init.initLogging(config);
            dispatcher = init.initDispatcher(config);
            init.initStaticContentLoader(config, dispatcher);

            prepare = new PrepareOperations(dispatcher);
            execute = new ExecuteOperations(dispatcher);
            this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

            postInit(dispatcher, filterConfig);
        } finally {
            if (dispatcher != null) {
                dispatcher.cleanUpAfterInit();
            }
            init.cleanup();
        }
    }

    /**
     * Callback for post initialization
     */
    protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) {
    }

    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);    //创建action的上下文
                prepare.assignDispatcherToThread();                //将Dispatcher放到本地线程中
                request = prepare.wrapRequest(request);
                ActionMapping mapping = prepare.findActionMapping(request, response, true);   // 找到action映射信息
                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);
        }
    }

    public void destroy() {
        prepare.cleanupDispatcher();
    }

}

接下来要学习的就是dofilter方法中的一些内容。在上面的代码中可以看出,首先我们要解决的就是prepare这个

对象。查看prepare对象对应的几个方法的源码如下:(不是很重要的方法笔者就直接截图了,比较方便)

1. prepare.setEncodingAndLocale(request, response);

这个方法就是在设置编码及本地化,不用过多关注




2.prepare.createActionContext(request, response);

创建action的上下文,并存放到本地线程中

    public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
        ActionContext ctx;
        Integer counter = 1;
        Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
        if (oldCounter != null) {
            counter = oldCounter + 1;
        }
        
        ActionContext oldContext = ActionContext.getContext();
        if (oldContext != null) {
             // 有旧的上下文存在,可以理解为请求转发
             // detected existing context, so we are probably in a forward
            ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
        } else {
             // 通过容器的值栈工厂创建一个值栈
             ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
             // 将request,response对象中存储的键值对,以map集合的形式存入到值栈的上下文中
             stack.getContext().putAll(dispatcher.createContextMap(request, response, null));
             // 以值栈的上下文构建一个新的actioncontext对象
            ctx = new ActionContext(stack.getContext());
        }
        request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
            // 将上下文对象存入到本地线程中        
         ActionContext.setContext(ctx);
         return ctx;
    }

下面对文中的注释做下简单解释

2.1: ActionContext.setContext(ctx);

这里稍微看一下Actioncontext的源码:


很明显,Actioncontext被存储在本地线程变量中,当我们调用set方法时,就是将Actioncontext对象存入到本

地线程中。

2.2.stack.getContext().putAll(dispatcher.createContextMap(request, response, null));

其实从方法名其参数名称上我们也能大概知道这个方法做了上面,不过我们还是稍微看下源码

首先,值栈的getContext()方法其实就是获得一个map集合


被框起来的部分已经很明显了,就不多说了

3.prepare.assignDispatcherToThread();

将Dispatcher对象放入到本地线程中,这里稍微看下代码就明白了,不做过多分析




4.request = prepare.wrapRequest(request);

将request对象进行包装成为MultiPartRequestWrapper或者StrutsRequestWrapper,就是对request中的

getAttribute方法进行了增强,稍微看下源码如下:


5. ActionMapping mapping = prepare.findActionMapping(request, response, true);

找到对象的action映射的信息,即actionMapping

    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;
    }

       dispatcher.getContainer().getInstance(ActionMapper.class)这段代码其实就是通过容器获取了一个

ActionMapper对象。所有的struts.xml配置文件的action信息都在ActionMapper上面。ActionMapper会判断

这个请求是否应该被struts2处理,并返回一个ActionMapping对象,并找到对应Action对象进行处理。

        另外代码request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping)这边所做的事情。功能意思

大家都能看得出来。那为什么这么做。主要还是因为后面的StrutsExecuteFilter类要用到。

这里最后补充一张图片,主要梳理值栈 request 上下文对象的存储关系:






猜你喜欢

转载自blog.csdn.net/qq_41907991/article/details/80773754