SpringMvc源码(二)--处理请求过程

1.处理请求

    过程: 1.请求首先进入到FrameworkServlet的processRequest中。

              2.调用DispatcherServlet中的doService方法,对请求进行预设置,doService方法在FrameworkServlet为抽象方法。

             3.最后调用DispatcherServlet的doDispatch方法,对请求进行处理,doDispatch方法为整个处理请求过程中的核心方法。

    processRequest方法

/**
     * FrameworkServlet中的processRequest方法
     */
    protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;
        //获取LocaleContextHolder中的LocaleContext
        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        //获取当前请求的LocaleContext,LocaleContext为本地化信息,如zh-cn,en-us等
        LocaleContext localeContext = buildLocaleContext(request);
        //获取RequestContextHolder保存的RequestAttributes
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        //获取当前请求的ServletRequestAttributes
        ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
        //异步请求管理器,关于异步请求放到后面说明
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
        //将当前请求的LocaleContext和RequestAttributes设置到LocaleContextHolder和RequestContextHolder中
        initContextHolders(request, localeContext, requestAttributes);
 
        try {
            //实际请求入口,抽象方法,在DispatcherServlet中实现
            doService(request, response);
        }
        catch (ServletException ex) {
            failureCause = ex;
            throw ex;
        }
        catch (IOException ex) {
            failureCause = ex;
            throw ex;
        }
        catch (Throwable ex) {
            failureCause = ex;
            throw new NestedServletException("Request processing failed", ex);
        }
 
        finally {
            //恢复原来的LocaleContext和RequestAttributes到LocaleContextHolder和RequestContextHolder中
            resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {
                requestAttributes.requestCompleted();
            }
 
            if (logger.isDebugEnabled()) {
                if (failureCause != null) {
                    this.logger.debug("Could not complete request", failureCause);
                }
                else {
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        logger.debug("Leaving response open for concurrent processing");
                    }
                    else {
                        this.logger.debug("Successfully completed request");
                    }
                }
            }
            publishRequestHandledEvent(request, startTime, failureCause);
        }
    }

doService方法,代码比较简单,主要做一些准备工作。

/**
     * DispatcherServlet中的doService方法
     * 省略注释以及日志代码
     * 在处理请求之前做一些准备工作
     */
    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, Object> attributesSnapshot = null;
        //判断是否是include请求,如果是的话需要对当前请求中的属性进行备份
        if (WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap<String, Object>();
            Enumeration<?> attrNames = request.getAttributeNames();
            while (attrNames.hasMoreElements()) {
                String attrName = (String) attrNames.nextElement();
                if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }
        //将一些组件设置到当前reuqest中,比如,springmvc容器,国际化资源解析器,主题解析器
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
        //对FlashMap进行更新
        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
 
        try {
            //真正处理请求的方法
            doDispatch(request, response);
        }
        finally {
            if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                return;
            }
            if (attributesSnapshot != null) {
                //对request中的属性进行恢复
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
    }

核心方法,doDispatch,先看一张图。

在看核心方法之前需要简单解释几个词,HandlerMapping,HandlerAdapter,ModelAndView,HandlerExecutionChain。

    HandlerMapping是之前提到过的SpringMvc中的一个组件,主要是通过request找到对应处理请求的方法Handler。

    HandlerAdapter 也是组件之一,作用是 使用找到的Handler处理请求。

    两者的关系可以简单理解为干活的工具和干活的人。当前请求request就是要干的活,干活需要工具,那么Handler就是用来干活的工具,有了工具,那么需要一个具体的人来干活,HandlerAdapter就是干活的人。连起来就是HandlerAdapter使用Handler处理请求,或者说Handler是一个方法,HandlerAdapter就是去执行这个方法的人。

    ModelAndView 比较简单易懂,处理完请求之后需要返回的视图以及传输到视图中的数据,都放在这里。

    HandlerExecutionChain,意思为处理器执行链,通过HandlerMapping所找到的就是一个处理器执行链,为什么叫链,用过springmvc的都知道,在处理一个请求之前可能会执行相关的拦截器,而这个HandlerExecutionChain对象中包含了处理请求的Handler和对应的拦截器,组合到一起称之为处理器执行链。

    解释了这几个东西之后,在来看相关源码。

 /**
     * DispatcherServlet中的doDispatch
     * 处理请求的核心方法
     */
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //当前请求
        HttpServletRequest processedRequest = request;
        //处理器执行链
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
 
        //异步请求
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
 
            try {
                //判断是否是上传请求
                processedRequest = checkMultipart(request);
                multipartRequestParsed = processedRequest != request;
                //使用HandlerMapping根据当前请求找到对应的方法和拦截器
                mappedHandler = getHandler(processedRequest, false);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
                //根据找到的Handler获取能够执行该Handler的HandlerAdapter
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
 
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        String requestUri = urlPathHelper.getRequestUri(request);
                        logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                //顺序执行所有拦截器的preHandle方法,如果某个preHandle方法值为false,那么直接return,请求结束
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
 
                try {
                    //处理请求,HandlerAdapter执行Handler方法
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                }
                finally {
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                }
                //设置默认视图名字
                applyDefaultViewName(request, mv);
                //倒序执行所有拦截器的postHandle方法
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            //渲染视图,包括处理请求过程中出现的异常视图都在这里处理
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            //倒序执行所有拦截器的afterCompletion方法
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            }
            if (multipartRequestParsed) {
                //如果是上传请求,清理资源
                cleanupMultipart(processedRequest);
            }
        }
    }

       一个请求到这里之后就算结束了。在这个方法中几乎用到了SpringMvc中的所有组件,具体每个组件的作用以及源码在后面的文章中会做一些分析。理解处理请求的过程最好还是打断点跟一遍源码,会理解的更快。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值