zoukankan      html  css  js  c++  java
  • 从DispatcherServlet中的doService了解spring组件之间的处理流程

    我了解DispatcherServlet中doService函数的目的是简单了解Spring各个组件之间的关系。

    DispatcherServlet的父类FrameworkServlet使用processRequest(request, response)函数来处理逻辑。它对request、response对象进行一些处理后,使用doService函数进行处理。

    DispatcherServlet 在doService中设置request的相关属性,然后调用doDispatch

        protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
            this.logRequest(request);
            Map<String, Object> attributesSnapshot = null;
            if (WebUtils.isIncludeRequest(request)) {
                attributesSnapshot = new HashMap();
                Enumeration attrNames = request.getAttributeNames();
    
                label95:
                while(true) {
                    String attrName;
                    do {
                        if (!attrNames.hasMoreElements()) {
                            break label95;
                        }
    
                        attrName = (String)attrNames.nextElement();
                    } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
    
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
    
            request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
            request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
            request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
            request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
            if (this.flashMapManager != null) {
                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 {
                this.doDispatch(request, response);
            } finally {
                if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
                    this.restoreAttributesAfterInclude(request, attributesSnapshot);
                }
    
            }
    
        }
    

      

    DispatcherServlet的doDispatch做了什么呢?它通过handlerMapping获得Handler,然后生成对应的HandlerAdapter来处理数据逻辑(controller层),获得了一个ModelAndView对象。HandlerAdpater 处理的结果是创建了一个ModelAndView对象,但不代表这个ModelAndView对象中包含了完整的信息。  随后DispatcherServlet使用RequestToViewNameResolver给ModelAndView设置viewName。最后调用processDispatchResult来处理界面逻辑(异常和view层)。

        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;
                    Object dispatchException = null;
    
                    try {
                        processedRequest = this.checkMultipart(request);
                        multipartRequestParsed = processedRequest != request;
                        mappedHandler = this.getHandler(processedRequest);
                        if (mappedHandler == null) {
                            this.noHandlerFound(processedRequest, response);
                            return;
                        }
    
                        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 ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                                return;
                            }
                        }
    
                        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                            return;
                        }
    
                        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                        if (asyncManager.isConcurrentHandlingStarted()) {
                            return;
                        }
    
                        this.applyDefaultViewName(processedRequest, mv);
                        mappedHandler.applyPostHandle(processedRequest, response, mv);
                    } catch (Exception var20) {
                        dispatchException = var20;
                    } catch (Throwable var21) {
                        dispatchException = new NestedServletException("Handler dispatch failed", var21);
                    }
    
                    this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
                } catch (Exception var22) {
                    this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
                } catch (Throwable var23) {
                    this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
                }
    
            } finally {
                if (asyncManager.isConcurrentHandlingStarted()) {
                    if (mappedHandler != null) {
                        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                    }
                } else if (multipartRequestParsed) {
                    this.cleanupMultipart(processedRequest);
                }
    
            }
        }
    

      

    DispatcherServlet的processDispatchResult首先会考虑异常的情况,如果有异常则使用HandlerExceptionResolver来处理异常,随后调用DispatcherServlet的render方法处理界面。

        private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
            boolean errorView = false;
            if (exception != null) {
                if (exception instanceof ModelAndViewDefiningException) {
                    this.logger.debug("ModelAndViewDefiningException encountered", exception);
                    mv = ((ModelAndViewDefiningException)exception).getModelAndView();
                } else {
                    Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
                    mv = this.processHandlerException(request, response, handler, exception);
                    errorView = mv != null;
                }
            }
    
            if (mv != null && !mv.wasCleared()) {
                this.render(mv, request, response);
                if (errorView) {
                    WebUtils.clearErrorRequestAttributes(request);
                }
            } else if (this.logger.isTraceEnabled()) {
                this.logger.trace("No view rendering, null ModelAndView returned.");
            }
    
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
                }
    
            }
        }
    

      

    DispatcherServlet的render方法使用ViewResolver从viewName(ModelAndView中)来得到一个View对象。最后让View对象使用ModelAndView来显示一个界面。

        protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
            Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
            response.setLocale(locale);
            String viewName = mv.getViewName();
            View view;
            if (viewName != null) {
                view = this.resolveViewName(viewName, 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 = 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.isTraceEnabled()) {
                this.logger.trace("Rendering view [" + view + "] ");
            }
    
            try {
                if (mv.getStatus() != null) {
                    response.setStatus(mv.getStatus().value());
                }
    
                view.render(mv.getModelInternal(), request, response);
            } catch (Exception var8) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Error rendering view [" + view + "]", var8);
                }
    
                throw var8;
            }
        }
    

      

    总结下:

    几个组件之间的执行流程是    handlerMapping  ———》 handlerAdapter————》requestToViewNameResolver ————》handlerExceptionResolver ————》 viewResolver ————》View

  • 相关阅读:
    SpringBoot使用Swagger2实现Restful API
    SpringBoot返回json和xml
    SpringBoot定时任务
    SpringBoot+Jpa+MySql学习
    SpringBoot+Mybatis+MySql学习
    linux安装jdk
    linux下安装mysql
    利用nginx,腾讯云免费证书制作https
    SpringBoot使用数据库
    SpringBoot的国际化使用
  • 原文地址:https://www.cnblogs.com/afraidToForget/p/10102909.html
Copyright © 2011-2022 走看看