• SpringMVC源码阅读-一个请求主要处理流程DispatcherServlet(四)


    流程图

    摘自:https://www.tianxiaobo.com/2018/06/29/Spring-MVC-原理探秘-一个请求的旅行过程/

    继承关系图

     1.GenericServlet 只是一个抽象类提供一些基础的模板 具体实现由以下子类实现

    2.HTTPServlet提供了对service的实现

    HttppServlet

    service

    javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)

     public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
            if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
                //转为HttpServletRequest
                HttpServletRequest request = (HttpServletRequest)req;
                //转为HttpServletResponse
                HttpServletResponse response = (HttpServletResponse)res;
                //<1>交给当前类的service方法处理 这里不是调用当前类的 而是调用子类FrameworkServlet的 重写了 子类会反向回调
                this.service(request, response);
            } else {
                throw new ServletException("non-HTTP request or response");
            }
        }

    <2>service

    javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)

    /**
         * 根据请求方式路由到对应的方法处理
         * @param req
         * @param resp
         * @throws ServletException
         * @throws IOException
         */
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获取请求协议头的请求方式 如:Request Method: GET
            String method = req.getMethod();
            long lastModified;
            if (method.equals("GET")) {
                //-1则表示缓存绝对更新了  默认子类没有实现 直接返回的-1
                lastModified = this.getLastModified(req);
                if (lastModified == -1L) {
                    //<3>根据协议版本 返回400 405空实现 由子类实现
                    this.doGet(req, resp);
                } else {
                    /**
                     *  <2>如果上一次请求客户端Last-Modified 如:Last-Modified: Thu, 20 Feb 2014 09:02:52 GMT
                     *  一般静态文件会默认带上
                     *  浏览器会将数据缓存本地
                     *  后续浏览器都会带上 每次跟服务器数据更新时间来做比较 如果没更新返回304 空响应
                     *  浏览器直接使用过本地数据
                     */
                    long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                    //比较缓存是否过期
                    if (ifModifiedSince < lastModified) {
                        this.maybeSetLastModified(resp, lastModified);
                        //<3>根据协议版本 返回400 405空实现 由子类实现
                        this.doGet(req, resp);
                    } else {
                        //返回304
                        resp.setStatus(304);
                    }
                }
            } else if (method.equals("HEAD")) {
                lastModified = this.getLastModified(req);
                this.maybeSetLastModified(resp, lastModified);
                this.doHead(req, resp);
            } else if (method.equals("POST")) {
                this.doPost(req, resp);
            } else if (method.equals("PUT")) {
                this.doPut(req, resp);
            } else if (method.equals("DELETE")) {
                this.doDelete(req, resp);
            } else if (method.equals("OPTIONS")) {
                this.doOptions(req, resp);
            } else if (method.equals("TRACE")) {
                this.doTrace(req, resp);
            } else {
                String errMsg = lStrings.getString("http.method_not_implemented");
                Object[] errArgs = new Object[]{method};
                errMsg = MessageFormat.format(errMsg, errArgs);
                resp.sendError(501, errMsg);
            }
    
        }

    <3>doGet

    路由的方法都在HettpServlet都是返回405或者400的空实现 会被子类重写

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String protocol = req.getProtocol();
            String msg = lStrings.getString("http.method_get_not_supported");
            if (protocol.endsWith("1.1")) {
                resp.sendError(405, msg);
            } else {
                resp.sendError(400, msg);
            }
    
        }

    org.springframework.web.servlet.FrameworkServlet的重写

      protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //<22>
    this.processRequest(request, response); } protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //<22>
    this.processRequest(request, response); } protected final void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //<22>
    this.processRequest(request, response); } protected final void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //<22>
    this.processRequest(request, response); }

    FrameworkServlet

    <1>service

    org.springframework.web.servlet.FrameworkServlet#service

     protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //如果请求方式是PATCH 则直接调用
            if (HttpMethod.PATCH.matches(request.getMethod())) {
    //<22>
    this.processRequest(request, response); } else { /** * 否则调用父类的路由方法 最终也是调用processRequest * <2>作用是是 比如父类的304缓存策略 以及路由的不同方法 处理方式 有所差异 如 option处理方式 */ super.service(request, response); } }

    <22>processRequest

    org.springframework.web.servlet.FrameworkServlet#service

    ->

    org.springframework.web.servlet.FrameworkServlet#processRequest

     protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            long startTime = System.currentTimeMillis();
            Throwable failureCause = null;
            /**
             * <31>获取当前线程 国际化上下文 从里面会从2个ThreadLocal获取
             * org.springframework.web.filter.RequestContextFilter#initContextHolders
             * 如果配置了这个filter这里每次请求已经初始化 spring boot 验证
             */
            LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
            //构建当前线程当本次请求的国际化上下文
            LocaleContext localeContext = this.buildLocaleContext(request);
            /**
             * <32>获取当前线程请求的RequestAttribute 里面会从2个ThreadLocal获取
             *  org.springframework.web.filter.RequestContextFilter#initContextHolders已经初始化 spring boot验证
             */
            RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
            //<4>如果线程缓存没有构建过,表示之前没初始化过 
            ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
            /**
             *会从requsetAttribute里面获取获取不到初始化一个再set进去 key=WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE
             * 表示我们后去都可以根据reqeust.getAttribute(WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE)获取
             * 用于给管理异步请求
             */
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
            /**
             * <5>这里面会存入根据当前对象成语变量区分放到哪个线程缓存里面threadContextInheritable 默认为false
             * 我们可以利用前面的BeanWapper进行修改
             * 表示我们后续都可以根据LocaleContextHolder和RequestContextHolder获取
             * 
             */
            this.initContextHolders(request, localeContext, requestAttributes);
    
            try {
                //<6>DispatcherServlet实现
                this.doService(request, response);
            } catch (ServletException var17) {
                failureCause = var17;
                throw var17;
            } catch (IOException var18) {
                failureCause = var18;
                throw var18;
            } catch (Throwable var19) {
                failureCause = var19;
                throw new NestedServletException("Request processing failed", var19);
            } finally {
                /**
                 *  <7>默认previousLocaleContext previousAttributes 是null
                 *  这里主要是为了将线程缓存的previousLocaleContext previousAttributes清空
                 */
                this.resetContextHolders(request, previousLocaleContext, previousAttributes);
                if (requestAttributes != null) {
                    requestAttributes.requestCompleted();
                }
    
                if (this.logger.isDebugEnabled()) {
                    if (failureCause != null) {
                        this.logger.debug("Could not complete request", (Throwable)failureCause);
                    } else if (asyncManager.isConcurrentHandlingStarted()) {
                        this.logger.debug("Leaving response open for concurrent processing");
                    } else {
                        this.logger.debug("Successfully completed request");
                    }
                }
                //spring事件机制 发布ServletRequestHandlerEvent消息,这个请求是否执行成功都会发布消息的
                this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
            }
    
        }

    <5>initContextHolders

     private void initContextHolders(HttpServletRequest request, @Nullable LocaleContext localeContext, @Nullable RequestAttributes requestAttributes) {
            if (localeContext != null) {
                LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
            }
    
            if (requestAttributes != null) {
                RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable);
            }
    
        }

    <31>getLocaleContext

    org.springframework.web.servlet.FrameworkServlet#service

    ->

    org.springframework.web.servlet.FrameworkServlet#processRequest

    ->

    org.springframework.context.i18n.LocaleContextHolder#getLocaleContext

     //继承ThreadLocal
        private static final ThreadLocal<LocaleContext> localeContextHolder = new NamedThreadLocal("Locale context");
        //继承inheritableThreadLocal 继承父线程的变量 但是子线程修改对父线程不可见(待测试)
        private static final ThreadLocal<LocaleContext> inheritableLocaleContextHolder = new NamedInheritableThreadLocal("Locale context");
        public static LocaleContext getLocaleContext() {
            //先从先从ThreadLocal里面获取哦
            LocaleContext localeContext = (LocaleContext)localeContextHolder.get();
            if (localeContext == null) {
                //获取不到从inheritableThreadLocal 获取
                localeContext = (LocaleContext)inheritableLocaleContextHolder.get();
            }
    
            return localeContext;
        }

    <32>getRequestAttributes

    org.springframework.web.servlet.FrameworkServlet#service

    ->

    org.springframework.web.servlet.FrameworkServlet#processRequest

    ->

    org.springframework.web.context.request.RequestContextHolder#getRequestAttributes

     //继承ThreadLocal
        private static final ThreadLocal<RequestAttributes> requestAttributesHolder = new NamedThreadLocal("Request attributes");
        //继承InheritableThreadLocal
        private static final ThreadLocal<RequestAttributes> inheritableRequestAttributesHolder = new NamedInheritableThreadLocal("Request context");
        public static RequestAttributes getRequestAttributes() {
            RequestAttributes attributes = (RequestAttributes)requestAttributesHolder.get();
            if (attributes == null) {
                attributes = (RequestAttributes)inheritableRequestAttributesHolder.get();
            }
    
            return attributes;
        }

    <4>buildRequestAttributes

    //如果之前没初始化过则构建一个新的
        protected ServletRequestAttributes buildRequestAttributes(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable RequestAttributes previousAttributes) {
            return previousAttributes != null && !(previousAttributes instanceof ServletRequestAttributes) ? null : new ServletRequestAttributes(request, response);
        }

    DispatcherServlet

    <6>doService

    org.springframework.web.servlet.FrameworkServlet#service

    ->

    org.springframework.web.servlet.FrameworkServlet#processRequest

    ->

    org.springframework.web.servlet.DispatcherServlet#doService

     protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
            if (this.logger.isDebugEnabled()) {
                String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
                this.logger.debug("DispatcherServlet with name '" + this.getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
            }
            //如果是include请求,保存request attribute快照数据,并在finally中进行还原
            Map<String, Object> attributesSnapshot = null;
            /**
             * request.getAttribute("javax.servlet.include.request_uri")!=null
             * <jsp:incluede page="xxx.jsp"/>
             * jsp里面嵌套上面这个标签 编译器后也是一个servlet来调用 通过这个属性判断是否是include标签
             */
            if (WebUtils.isIncludeRequest(request)) {
                attributesSnapshot = new HashMap();
                Enumeration attrNames = request.getAttributeNames();
    
                label108:
                while(true) {
                    String attrName;
                    do {
                        if (!attrNames.hasMoreElements()) {
                            break label108;
                        }
    
                        attrName = (String)attrNames.nextElement();
                    } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
    
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
            //保存ApplicationContext 到request
            request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
            //保存localeResolver 到request
            request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
            //保存themeResolver 到request
            request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
            //保存gThemeSource 到request
            request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
            //貌似是为了解决重定向302 带参数 长度问题 先保存到服务器 然后302重定向只需要带过来一个对应的key
            FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
            if (inputFlashMap != null) {
                request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
            }
    
            //保存一个空的FlashMap
            request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
            //保存flashMapManager
            request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    
            try {
                //<7>执行处理请求
                this.doDispatch(request, response);
            } finally {
                //还原快照数据
                if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
                    this.restoreAttributesAfterInclude(request, attributesSnapshot);
                }
    
            }
    
        }

    <7>doDispatch

     protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HttpServletRequest processedRequest = request;
            HandlerExecutionChain mappedHandler = null;
            boolean multipartRequestParsed = false;
            //获取异步管理器
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            try {
                try {
                    ModelAndView mv = null;
                    Exception dispatchException = null;
    
                    try {
                        /**
                         *<8> 如果配置了MultipartResolver 会调用 isMultipart() 方法判断请求中是否包含文件。
                         * 如果请求数据中包含文件,则调用 MultipartResolver 的 resolveMultipart()
                         * 方法对请求的数据进行解析,然后将文件数据解析成 MultipartFile
                         * 并封装在 MultipartHttpServletRequest (继承了 HttpServletRequest) 对象中并返回
                         */
                        processedRequest = this.checkMultipart(request);
                        //是否被解析
                        multipartRequestParsed = processedRequest != request;
                        //<9>通过HandlerMapping获得 HandlerExecutionChanin如:org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
                        //org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMappin
                        mappedHandler = this.getHandler(processedRequest);
                        if (mappedHandler == null || mappedHandler.getHandler() == null) {
                            //<10>没获取到抛出404异常
                            this.noHandlerFound(processedRequest, response);
                            return;
                        }
                        //<11>返回对应能处理的HandlerAdapter
                        HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                        String method = request.getMethod();
                        boolean isGet = "GET".equals(method);
                        if (isGet || "HEAD".equals(method)) {
                            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                            if (this.logger.isDebugEnabled()) {
                                this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                            }
    
                            if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                                return;
                            }
                        }
                        //<12>前置处理 拦截器
                        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                            return;
                        }
                         //<13>真正的处理方法 返回视图 没有视图则返回null
                        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                        //是否开启异步管理器
                        if (asyncManager.isConcurrentHandlingStarted()) {
                            return;
                        }
                        //<14>设置默认的viewName
                        this.applyDefaultViewName(processedRequest, mv);
                        //<15>后置处理 拦截器
                        mappedHandler.applyPostHandle(processedRequest, response, mv);
                    } catch (Exception var19) {
                        dispatchException = var19;
                    }
                    //<16> 处理正常和异常的请求调用结果。
                    this.processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
                } catch (Exception var20) {
                    //<17>触发异常拦截器的AfterCompletion实现
                    this.triggerAfterCompletion(processedRequest, response, mappedHandler, var20);
                } catch (Error var21) {
                    //<17>触发异常拦截器的AfterCompletion实现
                    this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, var21);
                }
    
            } finally {
                if (asyncManager.isConcurrentHandlingStarted()) {
                    if (mappedHandler != null) {
                        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                    }
                } else if (multipartRequestParsed) {
                    this.cleanupMultipart(processedRequest);
                }
    
            }
        }

     <8>checkMultipart

     protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
            //是否配置了multipartResolver 并且是否能处理
            if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
                if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
                    this.logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, this typically results from an additional MultipartFilter in web.xml");
                } else {
                    if (!(request.getAttribute("javax.servlet.error.exception") instanceof MultipartException)) {
                        //交给multipartResolver处理 并返回MultipartHttpServletRequest
                        return this.multipartResolver.resolveMultipart(request);
                    }
    
                    this.logger.debug("Multipart resolution failed for current request before - skipping re-resolution for undisturbed error rendering");
                }
            }
    
            return request;
        }

    <9>getHandler

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            //获得配置的handlerMapping
            Iterator var2 = this.handlerMappings.iterator();
    
            HandlerExecutionChain handler;
            do {
                if (!var2.hasNext()) {
                    return null;
                }
    
                HandlerMapping hm = (HandlerMapping)var2.next();
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
                }
              
                //适配 可参考org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler 
                handler = hm.getHandler(request);
            } while(handler == null);
    
            return handler;
        }

    <10>noHandlerFound

    protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
            if (pageNotFoundLogger.isWarnEnabled()) {
                pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) + "] in DispatcherServlet with name '" + this.getServletName() + "'");
            }
    
            if (this.throwExceptionIfNoHandlerFound) {
                throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request), (new ServletServerHttpRequest(request)).getHeaders());
            } else {
                response.sendError(404);
            }
        }

    <11>getHandlerAdapter

     protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
            //获得所有的handlerAdapters
            Iterator var2 = this.handlerAdapters.iterator();
    
            HandlerAdapter ha;
            do {
                if (!var2.hasNext()) {
                    throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
                }
                  
                ha = (HandlerAdapter)var2.next();
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Testing handler adapter [" + ha + "]");
                }
                //每次调用 handlerAdapters 对supports 判断是否能处理这个Handler
            } while(!ha.supports(handler));
    
            return ha;
        }

    <12>applyPreHandle

    org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
            //获得所有拦截器
            HandlerInterceptor[] interceptors = this.getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
                    HandlerInterceptor interceptor = interceptors[i];
                    //执行前置拦截
                    if (!interceptor.preHandle(request, response, this.handler)) {
                        //如果被拦截则触发拦截器的 完成后调用
                        this.triggerAfterCompletion(request, response, (Exception)null);
                        return false;
                    }
                }
            }
    
            return true;
        }

    <14>applyDefaultViewName

    org.springframework.web.servlet.DispatcherServlet#applyDefaultViewName

    private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
            //如果没有视图则设置默认视图
            if (mv != null && !mv.hasView()) {
                //
                mv.setViewName(this.getDefaultViewName(request));
            }
            
        }
        protected String getDefaultViewName(HttpServletRequest request) throws Exception {
            //通过viewNameTranslator 获得 我们可以自定义配置
            return this.viewNameTranslator.getViewName(request);
        }

    <15>applyPostHandle

    org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle

     void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
            //获得所有的拦截器
            HandlerInterceptor[] interceptors = this.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);
                }
            }
    
        }

    <16> processDispatchResult

    org.springframework.web.servlet.DispatcherServlet#processDispatchResult

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
            boolean errorView = false;
            //是否发生了异常
            if (exception != null) {
                //是否Controller正常处理返回ModelAndViewDefiningException
                if (exception instanceof ModelAndViewDefiningException) {
                    this.logger.debug("ModelAndViewDefiningException encountered", exception);
                    mv = ((ModelAndViewDefiningException)exception).getModelAndView();
                } else {
                    Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
                    //<18>触发异常拦截器 dispatcher init初始化
                    mv = this.processHandlerException(request, response, handler, exception);
                    errorView = mv != null;
                }
            }
    
            if (mv != null && !mv.wasCleared()) {
                //<20>交给viewResolvers 查找视图  dispatcher init初始化
                this.render(mv, request, response);
                if (errorView) {
                    WebUtils.clearErrorRequestAttributes(request);
                }
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
            }
    
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    //<17>触发拦截器的AfterCompletion
                    mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
                }
    
            }
        }

    <17>triggerAfterCompletion

     private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, Exception ex) throws Exception {
            if (mappedHandler != null) {
                mappedHandler.triggerAfterCompletion(request, response, ex);
            }
    
            throw ex;
        }
        private void triggerAfterCompletionWithError(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, Error error) throws Exception {
            ServletException ex = new NestedServletException("Handler processing failed", error);
            if (mappedHandler != null) {
                mappedHandler.triggerAfterCompletion(request, response, ex);
            }
    
            throw ex;
        }
    }

     <18>processHandlerException

    org.springframework.web.servlet.DispatcherServlet#processHandlerException

     protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            ModelAndView exMv = null;
            //获得所有的handlerExceptionResolver
            Iterator var6 = this.handlerExceptionResolvers.iterator();
    
            while (var6.hasNext()) {
                HandlerExceptionResolver handlerExceptionResolver = (HandlerExceptionResolver) var6.next();
                //执行官resolveException
                exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
                if (exMv != null) {
                    break;
                }
            }
    
            //是否返回了异常view 比如404 view
            if (exMv != null) {
                if (exMv.isEmpty()) {
                    request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
                    return null;
                } else {
                    if (!exMv.hasView()) {
                        exMv.setViewName(this.getDefaultViewName(request));
                    }
    
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
                    }
    
                    WebUtils.exposeErrorRequestAttributes(request, ex, this.getServletName());
                    return exMv;
                }
            } else {
                //抛出异常
                throw ex;
            }
        }

     <20>render

    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
            //调用localeResolver
            Locale locale = this.localeResolver.resolveLocale(request);
            response.setLocale(locale);
            View view;
            if (mv.isReference()) {
    //<21>根据viewResolver获得view view
    = this.resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'"); } } else { //获得view view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name '" + this.getServletName() + "'"); } } if (this.logger.isDebugEnabled()) { this.logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'"); } try { //解析 view.render(mv.getModelInternal(), request, response); } catch (Exception var7) { if (this.logger.isDebugEnabled()) { this.logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" + this.getServletName() + "'", var7); } throw var7; } }

     <21>resolveViewName

    org.springframework.web.servlet.DispatcherServlet#resolveViewName

        protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
            //viewResolvers dispatcher init初始化
            Iterator var5 = this.viewResolvers.iterator();
    
            View view;
            do {
                if (!var5.hasNext()) {
                    return null;
                }
    
                ViewResolver viewResolver = (ViewResolver)var5.next();
                //调用viewResolver 传入viewname查找视图
                view = viewResolver.resolveViewName(viewName, locale);
            } while(view == null);
    
            return view;
        }

    总结

    1.当一个请求来到FrameworkServlet最先收到请求
    2.交给父类httpServlet 父类根据请求方法做分发到FrameworkServlet的对应doGet doPost等方法
    3.doGet doPost 对应方法做一些特殊处理之后最终调用FrameworkServlet.processRequest 处理如:初始化requset域
    4.然后调用doService 由DispatcherServlet实现
      1.根据request获得对应的Handler 
      2.根据Handler获取对应的HandlerAdapter
      3.执行前置拦截器
      4.执行请求返回ModelView
      5.执行后置请求
      6.根据modelView进行处理 如果是视图则根据viewResolvers 查找对应的view
  • 相关阅读:
    移动端前端开发调试
    webkit图片滤镜
    ruby安装sass报错解决办法
    mongodb的查询语句学习摘要
    signedCookies
    [cookie篇]从cookie-parser中间件说起
    node.js下mongoose简单操作实例
    在ExpressJS中设置二级域名跨域共享Cookie
    Node.js开发工具、开发包、框架等总结
    hibernate框架学习笔记4:主键生成策略、对象状态
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12202596.html
Copyright © 2020-2023  润新知