Spring MVC原理(二)请求处理流程源码分析

请求的大概处理流程请参考这篇文章,这里摘来一张图。
http://www.jianshu.com/p/85a30095245e

《Spring MVC原理(二)请求处理流程源码分析》

DispatcherServlet作为流程控制的中心,整个请求的处理都是围绕这个servlet来进行。由名称可以看出这是一个servlet,具备普通servlet的所有的性质,既然是servlet肯定要在web.xml中配置,具体配置参考上面的文章。下面直接分析源码:

一个请求过来,只要是符合DispatcherServlet的拦截规则,web容器就会调用其doGet/doPost方法。

DispatcherServlet的继承体系和处理时序如下图所示:
《Spring MVC原理(二)请求处理流程源码分析》

DispatcherServlet的doGet/doPost方法的实现在其父类FrameworkServlet里面,

    /** * Delegate GET requests to processRequest/doService. * <p>Will also be invoked by HttpServlet's default implementation of {@code doHead}, * with a {@code NoBodyResponse} that just captures the content length. * @see #doService * @see #doHead */
    @Override
    protected final void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        processRequest(request, response);
    }

    /** * Delegate POST requests to {@link #processRequest}. * @see #doService */
    @Override
    protected final void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        processRequest(request, response);
    }

这里以Get方法为例分析整个处理过程:
(源码中省略了一些注释或者不重要的片段)

    protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;

        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        LocaleContext localeContext = buildLocaleContext(request);

        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

        initContextHolders(request, localeContext, requestAttributes);

        try {
            //doService的实现在DispatchServlet中
            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 {
            resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {
                requestAttributes.requestCompleted();
            }

            publishRequestHandledEvent(request, response, startTime, failureCause);
        }
    }
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // Keep a snapshot of the request attributes in case of an include,
        // to be able to restore the original attributes after the include.
        Map<String, Object> attributesSnapshot = null;
        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));
                }
            }
        }

        // Make framework objects available to handlers and view objects.
        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 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()) {
                // Restore the original attribute snapshot, in case of an include.
                if (attributesSnapshot != null) {
                    restoreAttributesAfterInclude(request, attributesSnapshot);
                }
            }
        }
    }
    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);

                // Determine handler for the current request.
                // 根据当前请求查找合适的处理器Handler
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // Actually invoke the handler.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }

                applyDefaultViewName(request, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        /* * HandlerMapping的作用是找到URL匹配的Handler对象,这里注册的HandlerMapping(handlerMappings中的元素)有三个: * 1)BeanNameUrlHandlerMapping: bean的name和url匹配 * 要求任何有可能处理请求的Bean都要起一个以反斜杠(/)字符开头的名称或者别名,这个名称或者别名可以是符合URL Path匹配原则中的任何名字。 * 它不能影射一个Prototype的Bean.换句话说,当使用 BeanNameUrlHandlerMapping时,所有的请求处理类只能是单例的(singletons) . 一般来 * 说,Controllers 都是按照单例建立的,所以这个并不是一个很严重的问题。 * 2)SimpleUrlHandlerMapping :直接匹配url和对应的bean(在mvc配置文件中配置,url和bean一一对应) * 由于BeanNameUrlHandlerMapping机制中URL和Handler是绑定在一起的,所以无法配置更为复杂的Mapping关系,SimpleUrlHandlerMapping * 可以看做是其的高级版,能够配置复杂的路径匹配关系,可以配置多组映射关系,把不同的URL映射到同一个handler对象。 * 3)RequestMappingHandlerMapping:专门处理注解@RequestMapping配置的类,和RequestMappingHandlerAdapter 对应起来使用 */
        for (HandlerMapping hm : this.handlerMappings) {
             /* * 遍历所有的HandlerMapping,找到能够处理当前request的一个 */
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        /* * */
        Object handler = getHandlerInternal(request);
        if (handler == null) { handler = getDefaultHandler();
        }
        if (handler == null) { return null;
        }
        // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        return getHandlerExecutionChain(handler, request);
    }
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //拿到请求的url
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        //根据请求的路径URL找到对应的处理方法(controller里的方法)
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        if (logger.isDebugEnabled()) {
            if (handlerMethod != null) {
                logger.debug("Returning handler method [" + handlerMethod + "]");
            }
            else {
                logger.debug("Did not find handler method for [" + lookupPath + "]");
            }
        }
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<Match>();
        /* * this.urlMap放的是当前这个HandlerMapping对象类型处理的URL和handler * 在Spring容器启动阶段,就已经把mvc配置文件或者controller类注解的映射关系添加到了 * urlMap里面,以匹配的URL作为键值。 */
        List<T> directPathMatches = this.urlMap.get(lookupPath);
        if (directPathMatches != null) {
            addMatchingMappings(directPathMatches, matches, request);
        }
        if (matches.isEmpty()) {
            // No choice but to go through all mappings...
            addMatchingMappings(this.handlerMethods.keySet(), matches, request);
        }

        if (!matches.isEmpty()) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            Collections.sort(matches, comparator);
            Match bestMatch = matches.get(0);
            if (matches.size() > 1) {
                Match secondBestMatch = matches.get(1);
                if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                    Method m1 = bestMatch.handlerMethod.getMethod();
                    Method m2 = secondBestMatch.handlerMethod.getMethod();
                    throw new IllegalStateException(
                            "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +
                            m1 + ", " + m2 + "}");
                }
            }
            handleMatch(bestMatch.mapping, lookupPath, request);
            return bestMatch.handlerMethod;
        }
        else {
            return handleNoMatch(handlerMethods.keySet(), lookupPath, request);
        }
    }
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
         /* * HandlerAdapter的作用是确定Handler对象中的哪个方法来处理当前URL,这里注册的HandlerAdapter有三种: * 1)HttpRequestHandlerAdapter:要求handler(controller)实现HttpRequestHandler接口 * 2)SimpleControllerHandlerAdapter:要求handler实现Controller接口 * 3)RequestMappingHandlerAdapter:和RequestMappingHandlerMapping配对使用,专门处理@RequestMapping 注解的类和方法 */
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (ha.supports(handler)) {
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }
    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/wutian713/article/details/54926044
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞