zoukankan      html  css  js  c++  java
  • 简单读!spring-mvc源码之穿越http请求

      相信spring-mvc这种被玩坏了的架构理念,大家都烂熟于胸了,不过还是想来扒一扒他的细节。

      一个http请求,怎么样被 spring 接收,又怎样做出响应呢?

    一般地,我们会配置一个 web.xml,然后开始代码之旅。

       在 web.xml 中配置 servlet-mapping, 将请求转发到 DispatcherServlet, 那么我们认为 DispatcherServlet 是我们的第一棒交接者!

        <servlet>
            <servlet-name>springMVC</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:applicationContext.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>springMVC</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>


    // tomcat 接到http请求后,会主动创建一个servlet, 然后调用进应用代码中, 创建的代码如下

            // Allocate a servlet instance to process this request
            try {
                if (!unavailable) {
                    servlet = wrapper.allocate();
                }
            } catch (ServletException e) {
                wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException",
                                 wrapper.getName()), StandardWrapper.getRootCause(e));
                servletException = e;
            } catch (Throwable e) {
                ExceptionUtils.handleThrowable(e);
                wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException",
                                 wrapper.getName()), e);
                servletException = new ServletException
                    (sm.getString("applicationDispatcher.allocateException",
                                  wrapper.getName()), e);
                servlet = null;
            }

    // org.apache.catalina.core.StandardWrapper.allocate(), 创建 servlet,

            
        /**
         * Allocate an initialized instance of this Servlet that is ready to have
         * its <code>service()</code> method called.  If the servlet class does
         * not implement <code>SingleThreadModel</code>, the (only) initialized
         * instance may be returned immediately.  If the servlet class implements
         * <code>SingleThreadModel</code>, the Wrapper implementation must ensure
         * that this instance is not allocated again until it is deallocated by a
         * call to <code>deallocate()</code>.
         *
         * @exception ServletException if the servlet init() method threw
         *  an exception
         * @exception ServletException if a loading error occurs
         */
        @Override
        public Servlet allocate() throws ServletException {
    
            // If we are currently unloading this servlet, throw an exception
            if (unloading) {
                throw new ServletException(sm.getString("standardWrapper.unloading", getName()));
            }
    
            boolean newInstance = false;
    
            // If not SingleThreadedModel, return the same instance every time
            if (!singleThreadModel) {
                // Load and initialize our instance if necessary
                if (instance == null || !instanceInitialized) {
                    synchronized (this) {
                        if (instance == null) {
                            try {
                                if (log.isDebugEnabled()) {
                                    log.debug("Allocating non-STM instance");
                                }
    
                                // Note: We don't know if the Servlet implements
                                // SingleThreadModel until we have loaded it.
                                instance = loadServlet();
                                newInstance = true;
                                if (!singleThreadModel) {
                                    // For non-STM, increment here to prevent a race
                                    // condition with unload. Bug 43683, test case
                                    // #3
                                    countAllocated.incrementAndGet();
                                }
                            } catch (ServletException e) {
                                throw e;
                            } catch (Throwable e) {
                                ExceptionUtils.handleThrowable(e);
                                throw new ServletException(sm.getString("standardWrapper.allocate"), e);
                            }
                        }
                        if (!instanceInitialized) {
                            initServlet(instance);
                        }
                    }
                }
    
                if (singleThreadModel) {
                    if (newInstance) {
                        // Have to do this outside of the sync above to prevent a
                        // possible deadlock
                        synchronized (instancePool) {
                            instancePool.push(instance);
                            nInstances++;
                        }
                    }
                } else {
                    if (log.isTraceEnabled()) {
                        log.trace("  Returning non-STM instance");
                    }
                    // For new instances, count will have been incremented at the
                    // time of creation
                    if (!newInstance) {
                        countAllocated.incrementAndGet();
                    }
                    return instance;
                }
            }
    
            synchronized (instancePool) {
                while (countAllocated.get() >= nInstances) {
                    // Allocate a new instance if possible, or else wait
                    if (nInstances < maxInstances) {
                        try {
                            instancePool.push(loadServlet());
                            nInstances++;
                        } catch (ServletException e) {
                            throw e;
                        } catch (Throwable e) {
                            ExceptionUtils.handleThrowable(e);
                            throw new ServletException(sm.getString("standardWrapper.allocate"), e);
                        }
                    } else {
                        try {
                            instancePool.wait();
                        } catch (InterruptedException e) {
                            // Ignore
                        }
                    }
                }
                if (log.isTraceEnabled()) {
                    log.trace("  Returning allocated STM instance");
                }
                countAllocated.incrementAndGet();
                return instancePool.pop();
            }
        }
    View Code

    // 最后,会先调用 filter, 完成之后再调用 servlet.service()

        private void internalDoFilter(ServletRequest request,
                                      ServletResponse response)
            throws IOException, ServletException {
    
            // Call the next filter if there is one
            if (pos < n) {
                ApplicationFilterConfig filterConfig = filters[pos++];
                try {
                    Filter filter = filterConfig.getFilter();
    
                    if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                            filterConfig.getFilterDef().getAsyncSupported())) {
                        request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
                    }
                    if( Globals.IS_SECURITY_ENABLED ) {
                        final ServletRequest req = request;
                        final ServletResponse res = response;
                        Principal principal =
                            ((HttpServletRequest) req).getUserPrincipal();
    
                        Object[] args = new Object[]{req, res, this};
                        SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
                    } else {
                        filter.doFilter(request, response, this);
                    }
                } catch (IOException | ServletException | RuntimeException e) {
                    throw e;
                } catch (Throwable e) {
                    e = ExceptionUtils.unwrapInvocationTargetException(e);
                    ExceptionUtils.handleThrowable(e);
                    throw new ServletException(sm.getString("filterChain.filter"), e);
                }
                return;
            }
    
            // We fell off the end of the chain -- call the servlet instance
            try {
                if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                    lastServicedRequest.set(request);
                    lastServicedResponse.set(response);
                }
    
                if (request.isAsyncSupported() && !servletSupportsAsync) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                            Boolean.FALSE);
                }
                // Use potentially wrapped request from this point
                if ((request instanceof HttpServletRequest) &&
                        (response instanceof HttpServletResponse) &&
                        Globals.IS_SECURITY_ENABLED ) {
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal =
                        ((HttpServletRequest) req).getUserPrincipal();
                    Object[] args = new Object[]{req, res};
                    SecurityUtil.doAsPrivilege("service",
                                               servlet,
                                               classTypeUsedInService,
                                               args,
                                               principal);
                } else {
                    servlet.service(request, response);
                }
            } catch (IOException | ServletException | RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                e = ExceptionUtils.unwrapInvocationTargetException(e);
                ExceptionUtils.handleThrowable(e);
                throw new ServletException(sm.getString("filterChain.servlet"), e);
            } finally {
                if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                    lastServicedRequest.set(null);
                    lastServicedResponse.set(null);
                }
            }
        }

    // 现在,到了 DispatcherServlet 出场了,由 DispatcherServlet 的父类 org.springframework.web.servlet.FrameworkServlet.service()接力, 开始处理

        /**
         * Override the parent class implementation in order to intercept PATCH requests.
         */
        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
            if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
                processRequest(request, response);
            }
            else {
                // 交由 HttpServlet.service() 处理,转发 doGet,doPost 等等方法
                super.service(request, response);
            }
        }
        
        // 父类 HttpServlet.service(), 只负责转发请求,由子类进行相应处理
        protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
        {
            String method = req.getMethod();
    
            if (method.equals(METHOD_GET)) {
                long lastModified = getLastModified(req);
                if (lastModified == -1) {
                    // servlet doesn't support if-modified-since, no reason
                    // to go through further expensive logic
                    doGet(req, resp);
                } else {
                    long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                    if (ifModifiedSince < lastModified) {
                        // If the servlet mod time is later, call doGet()
                        // Round down to the nearest second for a proper compare
                        // A ifModifiedSince of -1 will always be less
                        maybeSetLastModified(resp, lastModified);
                        doGet(req, resp);
                    } else {
                        resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                    }
                }
    
            } else if (method.equals(METHOD_HEAD)) {
                long lastModified = getLastModified(req);
                maybeSetLastModified(resp, lastModified);
                doHead(req, resp);
    
            } else if (method.equals(METHOD_POST)) {
                doPost(req, resp);
                
            } else if (method.equals(METHOD_PUT)) {
                doPut(req, resp);
                
            } else if (method.equals(METHOD_DELETE)) {
                doDelete(req, resp);
                
            } else if (method.equals(METHOD_OPTIONS)) {
                doOptions(req,resp);
                
            } else if (method.equals(METHOD_TRACE)) {
                doTrace(req,resp);
                
            } else {
                //
                // Note that this means NO servlet supports whatever
                // method was requested, anywhere on this server.
                //
    
                String errMsg = lStrings.getString("http.method_not_implemented");
                Object[] errArgs = new Object[1];
                errArgs[0] = method;
                errMsg = MessageFormat.format(errMsg, errArgs);
                
                resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
            }
        }

    // 比如 FrameworkServlet.doGet()/doXXX() 方法重写, 调用 processRequest()

        /**
         * 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);
        }
    View Code

    // FrameworkServlet.processRequest() 做一些全局设置,然后交由 doService() 进行具体处理, doService() 由子类实现,也即 DispatcherServlet.doService()

        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 {
                // 具体处理,交由 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 {
                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, response, startTime, failureCause);
            }
        }

    // locale 上下文管理

        private void initContextHolders(
                HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {
    
            //     private static final ThreadLocal<LocaleContext> localeContextHolder = new NamedThreadLocal<LocaleContext>("LocaleContext");
            if (localeContext != null) {
                LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
            }
            // private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal<RequestAttributes>("Request attributes");
            if (requestAttributes != null) {
                RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Bound request context to thread: " + request);
            }
        }

    // org.springframework.web.servlet.DispatcherServlet, 进行具体请求转发

        /**
         * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
         * for the actual dispatching.
         */
        @Override
        protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
            if (logger.isDebugEnabled()) {
                String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
                logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
                        " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
            }
    
            // 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(DEFAULT_STRATEGIES_PREFIX)) {
                        attributesSnapshot.put(attrName, request.getAttribute(attrName));
                    }
                }
            }
    
            // Make framework objects available to handlers and view objects.
            // 设备各种处理器到 request 中
            // 上下文管理
            request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
            // locale 管理
            request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
            // themeResolver
            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);
                    }
                }
            }
        }

    // doDispatch(), 实际分发方法

        /**
         * Process the actual dispatching to the handler.
         * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
         * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
         * to find the first that supports the handler class.
         * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
         * themselves to decide which methods are acceptable.
         * @param request current HTTP request
         * @param response current HTTP response
         * @throws Exception in case of any kind of processing failure
         */
        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 {
                    // 封装 multipart 文件上传,如果是文件上传类,则将其封装为 MultipartHttpServletRequest, 以便后续直接使用
                    processedRequest = checkMultipart(request);
                    multipartRequestParsed = (processedRequest != request);
    
                    // 获取具体uri业务处理器,即 由 RequestMapping 设置的路径
                    mappedHandler = getHandler(processedRequest);
                    if (mappedHandler == null || mappedHandler.getHandler() == null) {
                        // 如果没有找到 handler 则结束处理
                        noHandlerFound(processedRequest, response);
                        return;
                    }
    
                    // Determine handler adapter for the current request.
                    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                    // 对GET|HEAD 进行 last-modified 进行检测
                    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;
                    }
    
                    // 设置 view
                    applyDefaultViewName(processedRequest, mv);
                    // 后置处理
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                }
                catch (Exception ex) {
                    dispatchException = ex;
                }
                catch (Throwable err) {
                    // As of 4.3, we're processing Errors thrown from handler methods as well,
                    // making them available for @ExceptionHandler methods and other scenarios.
                    dispatchException = new NestedServletException("Handler dispatch failed", err);
                }
                // 最后再处理一次结果,如果有必要的话
                processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
            }
            catch (Exception ex) {
                triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
            }
            catch (Throwable err) {
                triggerAfterCompletion(processedRequest, response, mappedHandler,
                        new NestedServletException("Handler processing failed", 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);
                    }
                }
            }
        }

    // multipart 检测,需设置 multipartResolver, 方能转换,否则直接返回原始请求

        /**
         * Convert the request into a multipart request, and make multipart resolver available.
         * <p>If no multipart resolver is set, simply use the existing request.
         * @param request current HTTP request
         * @return the processed request (multipart wrapper if necessary)
         * @see MultipartResolver#resolveMultipart
         */
        protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
            if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
                if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
                    logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
                            "this typically results from an additional MultipartFilter in web.xml");
                }
                else if (hasMultipartException(request) ) {
                    logger.debug("Multipart resolution failed for current request before - " +
                            "skipping re-resolution for undisturbed error rendering");
                }
                else {
                    try {
                        // 调用 multipartResolver.resolveMultipart(), 由 resolver 进行文件转换处理
                        return this.multipartResolver.resolveMultipart(request);
                    }
                    catch (MultipartException ex) {
                        if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
                            logger.debug("Multipart resolution failed for error dispatch", ex);
                            // Keep processing error dispatch with regular request handle below
                        }
                        else {
                            throw ex;
                        }
                    }
                }
            }
            // If not returned before: return original request.
            return request;
        }
    View Code


    // 关键: 获取handler, 以待调用

        /**
         * Return the HandlerExecutionChain for this request.
         * <p>Tries all handler mappings in order.
         * @param request current HTTP request
         * @return the HandlerExecutionChain, or {@code null} if no handler could be found
         */
        protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            // handlerMappings 中保存了所有可用的路由
            for (HandlerMapping hm : this.handlerMappings) {
                if (logger.isTraceEnabled()) {
                    logger.trace(
                            "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
                }
                // 由具体的 HandlerMapping 去解析自己的映射
                HandlerExecutionChain handler = hm.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
            return null;
        }
    
        // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
        // org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler()
        /**
         * Look up a handler for the given request, falling back to the default
         * handler if no specific one is found.
         * @param request current HTTP request
         * @return the corresponding handler instance, or the default handler
         * @see #getHandlerInternal
         */
        @Override
        public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            // 获取 handlerMethod
            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);
            }
    
            // 获取 handler 链
            HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
            if (CorsUtils.isCorsRequest(request)) {
                CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
                CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
                CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
                executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
            }
            return executionChain;
        }
    
        // org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(), 查找 handler
        /**
         * Look up a handler method for the given request.
         */
        @Override
        protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
            // UrlHelper.getLookupPathForRequest() 进行路径分析
            String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
            if (logger.isDebugEnabled()) {
                logger.debug("Looking up handler method for path " + lookupPath);
            }
            // 加锁读取
            this.mappingRegistry.acquireReadLock();
            try {
                // 根据path查找 handlerMethod
                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 + "]");
                    }
                }
                // 找到匹配后,将 handler 通过 bean 查找方式包装进 HandlerMethod 中返回
                return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
            }
            finally {
                this.mappingRegistry.releaseReadLock();
            }
        }

    // 更细节的查询 handler 动作

    // org.springframework.web.util.UrlPathHelper
        /**
         * Return the mapping lookup path for the given request, within the current
         * servlet mapping if applicable, else within the web application.
         * <p>Detects include request URL if called within a RequestDispatcher include.
         * @param request current HTTP request
         * @return the lookup path
         * @see #getPathWithinApplication
         * @see #getPathWithinServletMapping
         */
        public String getLookupPathForRequest(HttpServletRequest request) {
            // Always use full path within current servlet context?
            if (this.alwaysUseFullPath) {
                return getPathWithinApplication(request);
            }
            // Else, use path within current servlet mapping if applicable
            String rest = getPathWithinServletMapping(request);
            if (!"".equals(rest)) {
                return rest;
            }
            else {
                // 返回 /hello/test
                return getPathWithinApplication(request);
            }
        }
    
        // 
        /**
         * Return the path within the servlet mapping for the given request,
         * i.e. the part of the request's URL beyond the part that called the servlet,
         * or "" if the whole URL has been used to identify the servlet.
         * <p>Detects include request URL if called within a RequestDispatcher include.
         * <p>E.g.: servlet mapping = "/*"; request URI = "/test/a" -> "/test/a".
         * <p>E.g.: servlet mapping = "/"; request URI = "/test/a" -> "/test/a".
         * <p>E.g.: servlet mapping = "/test/*"; request URI = "/test/a" -> "/a".
         * <p>E.g.: servlet mapping = "/test"; request URI = "/test" -> "".
         * <p>E.g.: servlet mapping = "/*.test"; request URI = "/a.test" -> "".
         * @param request current HTTP request
         * @return the path within the servlet mapping, or ""
         */
        public String getPathWithinServletMapping(HttpServletRequest request) {
            String pathWithinApp = getPathWithinApplication(request);
            String servletPath = getServletPath(request);
            String sanitizedPathWithinApp = getSanitizedPath(pathWithinApp);
            String path;
    
            // If the app container sanitized the servletPath, check against the sanitized version
            if (servletPath.contains(sanitizedPathWithinApp)) {
                path = getRemainingPath(sanitizedPathWithinApp, servletPath, false);
            }
            else {
                path = getRemainingPath(pathWithinApp, servletPath, false);
            }
    
            if (path != null) {
                // Normal case: URI contains servlet path.
                return path;
            }
            else {
                // Special case: URI is different from servlet path.
                String pathInfo = request.getPathInfo();
                if (pathInfo != null) {
                    // Use path info if available. Indicates index page within a servlet mapping?
                    // e.g. with index page: URI="/", servletPath="/index.html"
                    return pathInfo;
                }
                if (!this.urlDecode) {
                    // No path info... (not mapped by prefix, nor by extension, nor "/*")
                    // For the default servlet mapping (i.e. "/"), urlDecode=false can
                    // cause issues since getServletPath() returns a decoded path.
                    // If decoding pathWithinApp yields a match just use pathWithinApp.
                    path = getRemainingPath(decodeInternal(request, pathWithinApp), servletPath, false);
                    if (path != null) {
                        return pathWithinApp;
                    }
                }
                // Otherwise, use the full servlet path.
                return servletPath;
            }
        }
    
    
    // org.springframework.web.servlet.handler.AbstractHandlerMethodMapping 
        /**
         * Look up the best-matching handler method for the current request.
         * If multiple matches are found, the best match is selected.
         * @param lookupPath mapping lookup path within the current servlet mapping
         * @param request the current request
         * @return the best-matching handler method, or {@code null} if no match
         * @see #handleMatch(Object, String, HttpServletRequest)
         * @see #handleNoMatch(Set, String, HttpServletRequest)
         */
        protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
            List<Match> matches = new ArrayList<Match>();
            List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
            if (directPathMatches != null) {
                // 添加到匹配中,考虑不止一个匹配
                addMatchingMappings(directPathMatches, matches, request);
            }
            if (matches.isEmpty()) {
                // No choice but to go through all mappings...
                addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
            }
    
            if (!matches.isEmpty()) {
                // 如果有多个匹配,进行优先级排序,判断是否可用,然后取第一个作为最终的 handler
                Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
                Collections.sort(matches, comparator);
                if (logger.isTraceEnabled()) {
                    logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
                            lookupPath + "] : " + matches);
                }
                Match bestMatch = matches.get(0);
                if (matches.size() > 1) {
                    if (CorsUtils.isPreFlightRequest(request)) {
                        return PREFLIGHT_AMBIGUOUS_MATCH;
                    }
                    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 + "}");
                    }
                }
                // 解析参数到 handlerMethod 中
                handleMatch(bestMatch.mapping, lookupPath, request);
                return bestMatch.handlerMethod;
            }
            else {
                return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
            }
        }
        
        // AbstractHandlerMethodMapping$MappingRegistry.getMappingsByUrl()
            /**
             * Return matches for the given URL path. Not thread-safe.
             * @see #acquireReadLock()
             */
            public List<T> getMappingsByUrl(String urlPath) {
                // private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();
                // 内部使用 Map<K, List<V>> targetMap; 进行保存关系映射
                return this.urlLookup.get(urlPath);
            }
            
    
        // AbstractHandlerMethodMapping, 将确实有效的mapping添加到 matches 中
        private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
            for (T mapping : mappings) {
                // 重新严格校验路径,参数,header, 返回新的mapping
                T match = getMatchingMapping(mapping, request);
                if (match != null) {
                    // 将 handler 放入 match
                    // private class Match {}
                    matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
                }
            }
        }
    View Code


    // org.springframework.web.servlet.mvc.condition.HeadersRequestCondition
    // org.springframework.web.servlet.mvc.method.RequestMappingInfo
    // 进行参数校验,并封装返回参数信息到 RequestMappingInfo 中返回

        /**
         * Checks if all conditions in this request mapping info match the provided request and returns
         * a potentially new request mapping info with conditions tailored to the current request.
         * <p>For example the returned instance may contain the subset of URL patterns that match to
         * the current request, sorted with best matching patterns on top.
         * @return a new instance in case all conditions match; or {@code null} otherwise
         */
        @Override
        public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
            RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
            ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
            HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
            ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
            ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
    
            // 其中某个不匹配,则返回 null
            if (methods == null || params == null || headers == null || consumes == null || produces == null) {
                return null;
            }
    
            PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
            if (patterns == null) {
                return null;
            }
    
            RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
            if (custom == null) {
                return null;
            }
    
            return new RequestMappingInfo(this.name, patterns,
                    methods, params, headers, consumes, produces, custom.getCondition());
        }
        /**
         * Expose URI template variables, matrix variables, and producible media types in the request.
         * @see HandlerMapping#URI_TEMPLATE_VARIABLES_ATTRIBUTE
         * @see HandlerMapping#MATRIX_VARIABLES_ATTRIBUTE
         * @see HandlerMapping#PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE
         */
        @Override
        protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
            super.handleMatch(info, lookupPath, request);
    
            String bestPattern;
            Map<String, String> uriVariables;
            Map<String, String> decodedUriVariables;
    
            Set<String> patterns = info.getPatternsCondition().getPatterns();
            if (patterns.isEmpty()) {
                bestPattern = lookupPath;
                uriVariables = Collections.emptyMap();
                decodedUriVariables = Collections.emptyMap();
            }
            else {
                bestPattern = patterns.iterator().next();
                uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
                decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
            }
    
            request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
            request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);
    
            if (isMatrixVariableContentAvailable()) {
                Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables);
                request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);
            }
    
            if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
                Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
                request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
            }
        }
    View Code


    // org.springframework.web.method.HandlerMethod.createWithResolvedBean(), 重新包装一个带bean实例的 HandlerMethod

        /**
         * If the provided instance contains a bean name rather than an object instance,
         * the bean name is resolved before a {@link HandlerMethod} is created and returned.
         */
        public HandlerMethod createWithResolvedBean() {
            Object handler = this.bean;
            if (this.bean instanceof String) {
                String beanName = (String) this.bean;
                // spring beans 组件
                handler = this.beanFactory.getBean(beanName);
            }
            return new HandlerMethod(this, handler);
        }
        
        /**
         * Build a {@link HandlerExecutionChain} for the given handler, including
         * applicable interceptors.
         * <p>The default implementation builds a standard {@link HandlerExecutionChain}
         * with the given handler, the handler mapping's common interceptors, and any
         * {@link MappedInterceptor}s matching to the current request URL. Interceptors
         * are added in the order they were registered. Subclasses may override this
         * in order to extend/rearrange the list of interceptors.
         * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
         * pre-built {@link HandlerExecutionChain}. This method should handle those
         * two cases explicitly, either building a new {@link HandlerExecutionChain}
         * or extending the existing chain.
         * <p>For simply adding an interceptor in a custom subclass, consider calling
         * {@code super.getHandlerExecutionChain(handler, request)} and invoking
         * {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
         * @param handler the resolved handler instance (never {@code null})
         * @param request current HTTP request
         * @return the HandlerExecutionChain (never {@code null})
         * @see #getAdaptedInterceptors()
         */
        protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
            HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                    (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
    
            String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
            for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
                if (interceptor instanceof MappedInterceptor) {
                    MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                    if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                        // 取出内层的 interceptor 使用
                        chain.addInterceptor(mappedInterceptor.getInterceptor());
                    }
                }
                else {
                    chain.addInterceptor(interceptor);
                }
            }
            return chain;
        }

    // 获取 adapter,适配不同类型的调用

    // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
    // org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
    // org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
        /**
         * Return the HandlerAdapter for this handler object.
         * @param handler the handler object to find an adapter for
         * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
         */
        protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
            for (HandlerAdapter ha : this.handlerAdapters) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Testing handler adapter [" + ha + "]");
                }
                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");
        }
        


    // mappedHandler.applyPreHandle(processedRequest, response) , 前置调用处理, interceptor 拦截调用

        /**
         * Apply preHandle methods of registered interceptors.
         * @return {@code true} if the execution chain should proceed with the
         * next interceptor or the handler itself. Else, DispatcherServlet assumes
         * that this interceptor has already dealt with the response itself.
         */
        boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HandlerInterceptor[] interceptors = getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for (int i = 0; i < interceptors.length; i++) {
                    HandlerInterceptor interceptor = interceptors[i];
                    // 接收 preHandle 返回值, false 则终止
                    if (!interceptor.preHandle(request, response, this.handler)) {
                        triggerAfterCompletion(request, response, null);
                        return false;
                    }
                    this.interceptorIndex = i;
                }
            }
            return true;
        }


    // mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 真正调用 handler 处理业务
    // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
    // method.AbstractHandlerMethodAdapter

        /**
         * This implementation expects the handler to be an {@link HandlerMethod}.
         */
        @Override
        public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            // 内部调用
            return handleInternal(request, response, (HandlerMethod) handler);
        }
    
        // 
        @Override
        protected ModelAndView handleInternal(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
            ModelAndView mav;
            // 预检查是否可支持
            checkRequest(request);
    
            // Execute invokeHandlerMethod in synchronized block if required.
            if (this.synchronizeOnSession) {
                HttpSession session = request.getSession(false);
                if (session != null) {
                    Object mutex = WebUtils.getSessionMutex(session);
                    synchronized (mutex) {
                        mav = invokeHandlerMethod(request, response, handlerMethod);
                    }
                }
                else {
                    // No HttpSession available -> no mutex necessary
                    mav = invokeHandlerMethod(request, response, handlerMethod);
                }
            }
            else {
                // No synchronization on session demanded at all...
                // invoke
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
    
            if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
                if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                    applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
                }
                else {
                    prepareResponse(response);
                }
            }
    
            return mav;
        }
    //org.springframework.web.servlet.support.WebContentGenerator.checkRequest()
        /**
         * Check the given request for supported methods and a required session, if any.
         * @param request current HTTP request
         * @throws ServletException if the request cannot be handled because a check failed
         * @since 4.2
         */
        protected final void checkRequest(HttpServletRequest request) throws ServletException {
            // Check whether we should support the request method.
            String method = request.getMethod();
            if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
                throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
            }
    
            // Check whether a session is required.
            if (this.requireSession && request.getSession(false) == null) {
                throw new HttpSessionRequiredException("Pre-existing session required but none found");
            }
        }
    View Code


    // 调用 Adapter 的 handler 处理方法

        /**
         * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
         * if view resolution is required.
         * @since 4.2
         * @see #createInvocableHandlerMethod(HandlerMethod)
         */
        protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
            try {
                // 获取参数绑定工厂
                WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
                // 参数解析
                ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
    
                // createInvocableHandlerMethod, 反射调用工具类
                ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
                invocableMethod.setDataBinderFactory(binderFactory);
                invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    
                // mav
                ModelAndViewContainer mavContainer = new ModelAndViewContainer();
                mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
                modelFactory.initModel(webRequest, mavContainer, invocableMethod);
                mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    
                AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
                asyncWebRequest.setTimeout(this.asyncRequestTimeout);
    
                WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
                asyncManager.setTaskExecutor(this.taskExecutor);
                asyncManager.setAsyncWebRequest(asyncWebRequest);
                asyncManager.registerCallableInterceptors(this.callableInterceptors);
                asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
    
                if (asyncManager.hasConcurrentResult()) {
                    Object result = asyncManager.getConcurrentResult();
                    mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
                    asyncManager.clearConcurrentResult();
                    if (logger.isDebugEnabled()) {
                        logger.debug("Found concurrent result value [" + result + "]");
                    }
                    invocableMethod = invocableMethod.wrapConcurrentResult(result);
                }
    
                // 调用业务 controller
                invocableMethod.invokeAndHandle(webRequest, mavContainer);
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return null;
                }
    
                // 返回 mv, jsp, 如果是 json 一类的输出,则直接返回 null
                return getModelAndView(mavContainer, modelFactory, webRequest);
            }
            finally {
                webRequest.requestCompleted();
            }
        }

    细节点的工厂类创建:

        // 参数绑定工厂
        private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
            Class<?> handlerType = handlerMethod.getBeanType();
            Set<Method> methods = this.initBinderCache.get(handlerType);
            if (methods == null) {
                methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
                this.initBinderCache.put(handlerType, methods);
            }
            List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
            // Global methods first
            for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
                if (entry.getKey().isApplicableToBeanType(handlerType)) {
                    Object bean = entry.getKey().resolveBean();
                    for (Method method : entry.getValue()) {
                        initBinderMethods.add(createInitBinderMethod(bean, method));
                    }
                }
            }
            for (Method method : methods) {
                Object bean = handlerMethod.getBean();
                initBinderMethods.add(createInitBinderMethod(bean, method));
            }
            return createDataBinderFactory(initBinderMethods);
        }
    
        // 参数解析工厂
        private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
            SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
            Class<?> handlerType = handlerMethod.getBeanType();
            Set<Method> methods = this.modelAttributeCache.get(handlerType);
            if (methods == null) {
                methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
                this.modelAttributeCache.put(handlerType, methods);
            }
            List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
            // Global methods first
            for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
                if (entry.getKey().isApplicableToBeanType(handlerType)) {
                    Object bean = entry.getKey().resolveBean();
                    for (Method method : entry.getValue()) {
                        attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
                    }
                }
            }
            for (Method method : methods) {
                Object bean = handlerMethod.getBean();
                attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
            }
            return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
        }
        
    View Code

    // org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle()

        /**
         * Invoke the method and handle the return value through one of the
         * configured {@link HandlerMethodReturnValueHandler}s.
         * @param webRequest the current request
         * @param mavContainer the ModelAndViewContainer for this request
         * @param providedArgs "given" arguments matched by type (not resolved)
         */
        public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
    
            // 直接调用 handler
            Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
            // 设置响应码
            setResponseStatus(webRequest);
    
            if (returnValue == null) {
                if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
                    mavContainer.setRequestHandled(true);
                    return;
                }
            }
            else if (StringUtils.hasText(getResponseStatusReason())) {
                mavContainer.setRequestHandled(true);
                return;
            }
    
            mavContainer.setRequestHandled(false);
            try {
                // 处理返回值
                this.returnValueHandlers.handleReturnValue(
                        returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
            }
            catch (Exception ex) {
                if (logger.isTraceEnabled()) {
                    logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
                }
                throw ex;
            }
        }
        
        // InvocableHandlerMethod.invokeForRequest()
        /**
         * Invoke the method after resolving its argument values in the context of the given request.
         * <p>Argument values are commonly resolved through {@link HandlerMethodArgumentResolver}s.
         * The {@code providedArgs} parameter however may supply argument values to be used directly,
         * i.e. without argument resolution. Examples of provided argument values include a
         * {@link WebDataBinder}, a {@link SessionStatus}, or a thrown exception instance.
         * Provided argument values are checked before argument resolvers.
         * @param request the current request
         * @param mavContainer the ModelAndViewContainer for this request
         * @param providedArgs "given" arguments matched by type, not resolved
         * @return the raw value returned by the invoked method
         * @exception Exception raised if no suitable argument resolver can be found,
         * or if the method raised an exception
         */
        public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
    
            // 获取方法参数
            Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
            if (logger.isTraceEnabled()) {
                logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
                        "' with arguments " + Arrays.toString(args));
            }
            // invoke
            Object returnValue = doInvoke(args);
            if (logger.isTraceEnabled()) {
                logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
                        "] returned [" + returnValue + "]");
            }
            return returnValue;
        }

    // 参数封装,InvocableHandlerMethod.getMethodArgumentValues()

        // InvocableHandlerMethod.getMethodArgumentValues()
        /**
         * Get the method argument values for the current request.
         */
        private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
    
            MethodParameter[] parameters = getMethodParameters();
            Object[] args = new Object[parameters.length];
            for (int i = 0; i < parameters.length; i++) {
                MethodParameter parameter = parameters[i];
                parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
                args[i] = resolveProvidedArgument(parameter, providedArgs);
                if (args[i] != null) {
                    continue;
                }
                if (this.argumentResolvers.supportsParameter(parameter)) {
                    try {
                        args[i] = this.argumentResolvers.resolveArgument(
                                parameter, mavContainer, request, this.dataBinderFactory);
                        continue;
                    }
                    catch (Exception ex) {
                        if (logger.isDebugEnabled()) {
                            logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
                        }
                        throw ex;
                    }
                }
                if (args[i] == null) {
                    throw new IllegalStateException("Could not resolve method parameter at index " +
                            parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
                            ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
                }
            }
            return args;
        }
    
        
    // org.springframework.web.method.support.HandlerMethodArgumentResolverComposite
        /**
         * Iterate over registered {@link HandlerMethodArgumentResolver}s and invoke the one that supports it.
         * @throws IllegalStateException if no suitable {@link HandlerMethodArgumentResolver} is found.
         */
        @Override
        public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    
            HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
            if (resolver == null) {
                throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
            }
            return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
        }
    
    //    AbstractNamedValueMethodArgumentResolver
    
        @Override
        public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    
            NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
            MethodParameter nestedParameter = parameter.nestedIfOptional();
    
            // 处理 key
            Object resolvedName = resolveStringValue(namedValueInfo.name);
            if (resolvedName == null) {
                throw new IllegalArgumentException(
                        "Specified name must not resolve to null: [" + namedValueInfo.name + "]");
            }
    
            // 获取 value
            Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest);
            if (arg == null) {
                if (namedValueInfo.defaultValue != null) {
                    arg = resolveStringValue(namedValueInfo.defaultValue);
                }
                else if (namedValueInfo.required && !nestedParameter.isOptional()) {
                    handleMissingValue(namedValueInfo.name, nestedParameter, webRequest);
                }
                arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
            }
            else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
                arg = resolveStringValue(namedValueInfo.defaultValue);
            }
    
            if (binderFactory != null) {
                WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
                try {
                    arg = binder.convertIfNecessary(arg, parameter.getParameterType(), parameter);
                }
                catch (ConversionNotSupportedException ex) {
                    throw new MethodArgumentConversionNotSupportedException(arg, ex.getRequiredType(),
                            namedValueInfo.name, parameter, ex.getCause());
                }
                catch (TypeMismatchException ex) {
                    throw new MethodArgumentTypeMismatchException(arg, ex.getRequiredType(),
                            namedValueInfo.name, parameter, ex.getCause());
    
                }
            }
    
            handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
    
            return arg;
        }
    View Code

    // Object returnValue = doInvoke(args); 
    // InvocableHandlerMethod.doInvoke(), 正常返回结果,异常包装返回

        /**
         * Invoke the handler method with the given argument values.
         */
        protected Object doInvoke(Object... args) throws Exception {
            // 确保方法可调用
            ReflectionUtils.makeAccessible(getBridgedMethod());
            try {
                // 调用业务方法
                return getBridgedMethod().invoke(getBean(), args);
            }
            catch (IllegalArgumentException ex) {
                assertTargetBean(getBridgedMethod(), getBean(), args);
                String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
                throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
            }
            catch (InvocationTargetException ex) {
                // Unwrap for HandlerExceptionResolvers ...
                Throwable targetException = ex.getTargetException();
                if (targetException instanceof RuntimeException) {
                    throw (RuntimeException) targetException;
                }
                else if (targetException instanceof Error) {
                    throw (Error) targetException;
                }
                else if (targetException instanceof Exception) {
                    throw (Exception) targetException;
                }
                else {
                    String text = getInvocationErrorMessage("Failed to invoke handler method", args);
                    throw new IllegalStateException(text, targetException);
                }
            }
        }


    // 至此业务方法终于调用完成

    // 接下来,处理返回值

    // this.returnValueHandlers.handleReturnValue(
    //                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    // org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue()
        /**
         * Iterate over registered {@link HandlerMethodReturnValueHandler}s and invoke the one that supports it.
         * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
         */
        @Override
        public void handleReturnValue(Object returnValue, MethodParameter returnType,
                ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    
            HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
            if (handler == null) {
                throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
            }
            handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
        }
    
    // 返回值处理器
    // org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler
    // org.springframework.web.method.annotation.ModelMethodProcessor
    // org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler
    // org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler
    // org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler
    // org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor
    // org.springframework.web.servlet.mvc.method.annotation.HttpHeadersReturnValueHandler
    // org.springframework.web.servlet.mvc.method.annotation.CallableMethodReturnValueHandler
    // org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler
    // org.springframework.web.servlet.mvc.method.annotation.AsyncTaskMethodReturnValueHandler
    // org.springframework.web.method.annotation.ModelAttributeMethodProcessor
    // org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
    // org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler
    // org.springframework.web.method.annotation.MapMethodProcessor
    // org.springframework.web.method.annotation.ModelAttributeMethodProcessor
        private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
            boolean isAsyncValue = isAsyncReturnValue(value, returnType);
            for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
                if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
                    continue;
                }
                // return Callable.class.isAssignableFrom(returnType.getParameterType());
                // return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
                //    returnType.hasMethodAnnotation(ResponseBody.class));
                if (handler.supportsReturnType(returnType)) {
                    return handler;
                }
            }
            return null;
        }
    
        // org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(), 处理返回结果
        @Override
        public void handleReturnValue(Object returnValue, MethodParameter returnType,
                ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
                throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
    
            mavContainer.setRequestHandled(true);
            ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
            ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
    
            // 写返回值
            // Try even with null return value. ResponseBodyAdvice could get involved.
            writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
        }
    
        
        /**
         * Creates a new {@link HttpOutputMessage} from the given {@link NativeWebRequest}.
         * @param webRequest the web request to create an output message from
         * @return the output message
         */
        protected ServletServerHttpResponse createOutputMessage(NativeWebRequest webRequest) {
            HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
            return new ServletServerHttpResponse(response);
        }
        
        
        /**
         * Writes the given return type to the given output message.
         * @param value the value to write to the output message
         * @param returnType the type of the value
         * @param inputMessage the input messages. Used to inspect the {@code Accept} header.
         * @param outputMessage the output message to write to
         * @throws IOException thrown in case of I/O errors
         * @throws HttpMediaTypeNotAcceptableException thrown when the conditions indicated
         * by the {@code Accept} header on the request cannot be met by the message converters
         */
        @SuppressWarnings("unchecked")
        protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
                ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
                throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
    
            Object outputValue;
            Class<?> valueType;
            Type declaredType;
    
            if (value instanceof CharSequence) {
                // string 的返回值输出
                outputValue = value.toString();
                valueType = String.class;
                declaredType = String.class;
            }
            else {
                outputValue = value;
                valueType = getReturnValueType(outputValue, returnType);
                declaredType = getGenericType(returnType);
            }
    
            HttpServletRequest request = inputMessage.getServletRequest();
            // 获取返回的 content-type 值
            List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
            List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
    
            if (outputValue != null && producibleMediaTypes.isEmpty()) {
                throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
            }
    
            Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
            for (MediaType requestedType : requestedMediaTypes) {
                for (MediaType producibleType : producibleMediaTypes) {
                    if (requestedType.isCompatibleWith(producibleType)) {
                        compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
                    }
                }
            }
            if (compatibleMediaTypes.isEmpty()) {
                if (outputValue != null) {
                    throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
                }
                return;
            }
    
            List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
            MediaType.sortBySpecificityAndQuality(mediaTypes);
    
            // 确定输出的类型
            MediaType selectedMediaType = null;
            for (MediaType mediaType : mediaTypes) {
                if (mediaType.isConcrete()) {
                    selectedMediaType = mediaType;
                    break;
                }
                else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
                    selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
                    break;
                }
            }
    
            if (selectedMediaType != null) {
                selectedMediaType = selectedMediaType.removeQualityValue();
                // 使用 messageConverter 进行返回值转换
                // org.springframework.http.converter.ByteArrayHttpMessageConverter
                // org.springframework.http.converter.StringHttpMessageConverter
                // org.springframework.http.converter.ResourceHttpMessageConverter
                // org.springframework.http.converter.xml.SourceHttpMessageConverter
                // org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
                // org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter
                // org.springframework.http.converter.ByteArrayHttpMessageConverter
                // org.springframework.http.converter.StringHttpMessageConverter
                // org.springframework.http.converter.ResourceHttpMessageConverter
                // org.springframework.http.converter.xml.SourceHttpMessageConverter
                // org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
                // org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter
                for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
                    if (messageConverter instanceof GenericHttpMessageConverter) {
                        if (((GenericHttpMessageConverter) messageConverter).canWrite(
                                declaredType, valueType, selectedMediaType)) {
                            outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
                                    (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
                                    inputMessage, outputMessage);
                            if (outputValue != null) {
                                addContentDispositionHeader(inputMessage, outputMessage);
                                ((GenericHttpMessageConverter) messageConverter).write(
                                        outputValue, declaredType, selectedMediaType, outputMessage);
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Written [" + outputValue + "] as "" + selectedMediaType +
                                            "" using [" + messageConverter + "]");
                                }
                            }
                            return;
                        }
                    }
                    else if (messageConverter.canWrite(valueType, selectedMediaType)) {
                        // 输出值
                        outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
                                (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
                                inputMessage, outputMessage);
                        if (outputValue != null) {
                            addContentDispositionHeader(inputMessage, outputMessage);
                            // write
                            ((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);
                            if (logger.isDebugEnabled()) {
                                logger.debug("Written [" + outputValue + "] as "" + selectedMediaType +
                                        "" using [" + messageConverter + "]");
                            }
                        }
                        return;
                    }
                }
            }
    
            if (outputValue != null) {
                throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
            }
        }

    // 消息转换器

    // org.springframework.http.converter.StringHttpMessageConverter
    // org.springframework.http.converter.AbstractHttpMessageConverter

    // org.springframework.http.converter.StringHttpMessageConverter
    // org.springframework.http.converter.AbstractHttpMessageConverter
        /**
         * This implementation sets the default headers by calling {@link #addDefaultHeaders},
         * and then calls {@link #writeInternal}.
         */
        @Override
        public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage)
                throws IOException, HttpMessageNotWritableException {
    
            final HttpHeaders headers = outputMessage.getHeaders();
            addDefaultHeaders(headers, t, contentType);
    
            if (outputMessage instanceof StreamingHttpOutputMessage) {
                StreamingHttpOutputMessage streamingOutputMessage =
                        (StreamingHttpOutputMessage) outputMessage;
                streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() {
                    @Override
                    public void writeTo(final OutputStream outputStream) throws IOException {
                        writeInternal(t, new HttpOutputMessage() {
                            @Override
                            public OutputStream getBody() throws IOException {
                                return outputStream;
                            }
                            @Override
                            public HttpHeaders getHeaders() {
                                return headers;
                            }
                        });
                    }
                });
            }
            else {
                // write
                writeInternal(t, outputMessage);
                // 再次 flush()
                outputMessage.getBody().flush();
            }
        }
    
        // StringHttpMessageConverter
        @Override
        protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
            if (this.writeAcceptCharset) {
                outputMessage.getHeaders().setAcceptCharset(getAcceptedCharsets());
            }
            Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());
            StreamUtils.copy(str, charset, outputMessage.getBody());
        }
    
        // org.springframework.util.StreamUtils.copy()
        // 像socket中写入返回值,即向浏览器一类请求客户端输出返回值,到此,客户端得到响应
        /**
         * Copy the contents of the given String to the given output OutputStream.
         * Leaves the stream open when done.
         * @param in the String to copy from
         * @param charset the Charset
         * @param out the OutputStream to copy to
         * @throws IOException in case of I/O errors
         */
        public static void copy(String in, Charset charset, OutputStream out) throws IOException {
            Assert.notNull(in, "No input String specified");
            Assert.notNull(charset, "No charset specified");
            Assert.notNull(out, "No OutputStream specified");
    
            Writer writer = new OutputStreamWriter(out, charset);
            writer.write(in);
            writer.flush();
        }


    // return getModelAndView(mavContainer, modelFactory, webRequest);
    // RequestMappingHandlerAdapter

    // return getModelAndView(mavContainer, modelFactory, webRequest);
    // RequestMappingHandlerAdapter
        private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
                ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
    
            // 如果已经处理完成,返回null
            modelFactory.updateModel(webRequest, mavContainer);
            if (mavContainer.isRequestHandled()) {
                return null;
            }
            // 否则处理 mv
            ModelMap model = mavContainer.getModel();
            ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
            if (!mavContainer.isViewReference()) {
                mav.setView((View) mavContainer.getView());
            }
            if (model instanceof RedirectAttributes) {
                Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
                HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
                RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
            }
            return mav;
        }


    // prepareResponse(response);
    // RequestMappingHandlerAdapter

        /**
         * Prepare the given response according to the settings of this generator.
         * Applies the number of cache seconds specified for this generator.
         * @param response current HTTP response
         * @since 4.2
         */
        protected final void prepareResponse(HttpServletResponse response) {
            if (this.cacheControl != null) {
                applyCacheControl(response, this.cacheControl);
            }
            else {
                applyCacheSeconds(response, this.cacheSeconds);
            }
            if (servlet3Present && this.varyByRequestHeaders != null) {
                for (String value : getVaryRequestHeadersToAdd(response)) {
                    response.addHeader("Vary", value);
                }
            }
        }
    View Code


    // mappedHandler.applyPostHandle(processedRequest, response, mv);
    // org.springframework.web.servlet.HandlerExecutionChain.applyPostHandle(), 调用 interceptor.postHandle()

    // org.springframework.web.servlet.HandlerExecutionChain.applyPostHandle(), 调用 interceptor.postHandle()
        /**
         * Apply postHandle methods of registered interceptors.
         */
        void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
            HandlerInterceptor[] interceptors = getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for (int i = interceptors.length - 1; i >= 0; i--) {
                    HandlerInterceptor interceptor = interceptors[i];
                    interceptor.postHandle(request, response, this.handler, mv);
                }
            }
        }



    // processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

        /**
         * Handle the result of handler selection and handler invocation, which is
         * either a ModelAndView or an Exception to be resolved to a ModelAndView.
         */
        private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
    
            boolean errorView = false;
    
            // 发生异常,使用 errorView
            if (exception != null) {
                if (exception instanceof ModelAndViewDefiningException) {
                    logger.debug("ModelAndViewDefiningException encountered", exception);
                    mv = ((ModelAndViewDefiningException) exception).getModelAndView();
                }
                else {
                    Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                    mv = processHandlerException(request, response, handler, exception);
                    errorView = (mv != null);
                }
            }
    
            // Did the handler return a view to render?
            if (mv != null && !mv.wasCleared()) {
                render(mv, request, response);
                if (errorView) {
                    WebUtils.clearErrorRequestAttributes(request);
                }
            }
            else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                            "': assuming HandlerAdapter completed request handling");
                }
            }
    
            if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                // Concurrent handling started during a forward
                return;
            }
    
            if (mappedHandler != null) {
                // 最后再一个触发器钩子,触发 interceptor.afterCompletion()
                mappedHandler.triggerAfterCompletion(request, response, null);
            }
        }
    
        
        /**
         * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
         * Will just invoke afterCompletion for all interceptors whose preHandle invocation
         * has successfully completed and returned true.
         */
        void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
                throws Exception {
    
            HandlerInterceptor[] interceptors = getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for (int i = this.interceptorIndex; i >= 0; i--) {
                    HandlerInterceptor interceptor = interceptors[i];
                    try {
                        interceptor.afterCompletion(request, response, this.handler, ex);
                    }
                    catch (Throwable ex2) {
                        logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
                    }
                }
            }
        }


    // 依次返回 doDispatch(),清理环境
    // 返回 FrameworkServlet.doService()

    // FrameworkServlet finally中还会触发 requestAttributes.requestCompleted();

    // org.springframework.web.context.request.ServletRequestAttributes.requestCompleted()
        /**
         * Signal that the request has been completed.
         * <p>Executes all request destruction callbacks and updates the
         * session attributes that have been accessed during request processing.
         */
        public void requestCompleted() {
            executeRequestDestructionCallbacks();
            updateAccessedSessionAttributes();
            this.requestActive = false;
        }
        
        /**
         * Execute all callbacks that have been registered for execution
         * after request completion.
         */
        private void executeRequestDestructionCallbacks() {
            synchronized (this.requestDestructionCallbacks) {
                for (Runnable runnable : this.requestDestructionCallbacks.values()) {
                    // 同步调用 DestructionCallbacks.run()
                    runnable.run();
                }
                this.requestDestructionCallbacks.clear();
            }
        }
    
        /**
         * Update all accessed session attributes through {@code session.setAttribute}
         * calls, explicitly indicating to the container that they might have been modified.
         */
        @Override
        protected void updateAccessedSessionAttributes() {
            if (!this.sessionAttributesToUpdate.isEmpty()) {
                // Update all affected session attributes.
                HttpSession session = getSession(false);
                if (session != null) {
                    try {
                        for (Map.Entry<String, Object> entry : this.sessionAttributesToUpdate.entrySet()) {
                            String name = entry.getKey();
                            Object newValue = entry.getValue();
                            Object oldValue = session.getAttribute(name);
                            if (oldValue == newValue && !isImmutableSessionAttribute(name, newValue)) {
                                session.setAttribute(name, newValue);
                            }
                        }
                    }
                    catch (IllegalStateException ex) {
                        // Session invalidated - shouldn't usually happen.
                    }
                }
                this.sessionAttributesToUpdate.clear();
            }
        }
    
    // 最后 publishRequestHandledEvent(request, response, startTime, failureCause);
    // FrameworkServlet
        private void publishRequestHandledEvent(
                HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {
    
            if (this.publishEvents) {
                // Whether or not we succeeded, publish an event.
                long processingTime = System.currentTimeMillis() - startTime;
                int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);
                // 发布 event 到 spring, 使感兴趣的监听者进行相应处理
                this.webApplicationContext.publishEvent(
                        new ServletRequestHandledEvent(this,
                                request.getRequestURI(), request.getRemoteAddr(),
                                request.getMethod(), getServletConfig().getServletName(),
                                WebUtils.getSessionId(request), getUsernameForRequest(request),
                                processingTime, failureCause, statusCode));
            }
        }

           总结几个技术要点:

               1. filterchain 责任链模式的使用;

               2. 工厂模式的使用;

               3. 拦截器监听;

               4. 各功能组件化,职责分明;

               5. 模板方法模式使用;

               6. mvc;

               7. 适配器模式应用;

               8. 观察者模式应用;

  • 相关阅读:
    MySQL查询优化程序
    mysql主从:主键冲突问题
    Cacti 'graph_xport.php' SQL注入漏洞
    Nginx SPDY缓冲区溢出漏洞
    Zend Framework XML外部实体和安全绕过漏洞
    WordPress 3.8.1 /xmlrpc.php拒绝服务漏洞
    OpenSSH 'child_set_env()'函数安全绕过漏洞
    PHP "gdImageCreateFromXpm()"空指针间接引用漏洞
    Apache HTTP Server多个拒绝服务漏洞
    Samba 安全漏洞
  • 原文地址:https://www.cnblogs.com/yougewe/p/9942159.html
Copyright © 2011-2022 走看看