SpringMVC 流程分析

jopen 10年前發布 | 40K 次閱讀 SpringMVC Spring MVC Web框架

SpringMVC 流程

服務器啟動階段(DispatcherServlet初始化階段)

  1. 啟動后ContextLoaderListener首先會在初始化方法contextInitialized(ServletContextEvent event)中調用initWebApplicationContext(event.getServletContext())來在創建一個WebApplicationContext。并將其作為ServletContext的一個屬性設置到Servlet環境中。這個上下文對象為跟上下文對象。
    ContextLoader#initWebApplicationContext(ServletContext servletContext)

    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
  2. DispatcherServlet初始化過程中中也會創建一個WebApplicationContext對象,并將ContextLoaderListener創建的上下文對象作為父上下文。同樣也會將其作為ServletContext的一個屬性。
    FrameworkServlet#initWebApplicationContext()

    String attrName = getServletContextAttributeName();    
    getServletContext().setAttribute(attrName, wac);

    創建完上下文對象后還會調用onRefresh進行一系列初始化工作。
    DispatcherServlet#initStrategies(ApplicationContext context)

    initMultipartResolver(context); 
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);

    這幾個init方法的實現思路基本相同,首先從Bean容器中過的特定類型的類的實例。如果沒有找到,則使用默認配置。即DispatcherServlet.properties中的配置。
    DispatcherServlet#initHandlerAdapters(ApplicationContext context)

    private void initHandlerAdapters(ApplicationContext context) {
        this.handlerAdapters = null;
    
        if (this.detectAllHandlerAdapters) {
            // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
            Map<String, HandlerAdapter> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
                // We keep HandlerAdapters in sorted order.
                // 排序后對后來的getHandlerAdapter的結果會有所影響
                OrderComparator.sort(this.handlerAdapters);
            }
        }
        else {
            try {
                HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
                this.handlerAdapters = Collections.singletonList(ha);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerAdapter later.
            }
        }
    
        // Ensure we have at least some HandlerAdapters, by registering
        // default HandlerAdapters if no other adapters are found.
        if (this.handlerAdapters == null) {
            this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
            }
        }
    }

經過一系列的init方法后DispatcherServlet正式初始化完成。

請求-響應階段

  1. 發起請求
    DispatcherServlet是一個標準的Servlet。當我們發送一個GET請求后,會有DispatcherServletdoGet(HttpServletRequest request, HttpServletResponse response)來處理。
    FrameworkServlet#doGet(HttpServletRequest request, HttpServletResponse response)

    processRequest(request, response);

    processRequest這一階段主要調用doService,然后是doDispatch

  2. 處理請求
    doDispatch主要有一下幾步操作。
    1) 首先調用getHandler首先獲得一個HandlerMapping對象,然后調用其getHandler方法返回一個HandlerExecutionChain對象。具體查看HandlerMapping實現類,例如RequestMappingHandlerMapping
    DispatcherServlet#getHandler(HttpServletRequest request)

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
            }
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }

    RequestMethodHandlerMapping為例,此對象中主要包含一個HandlerMethod實例及處理此請求的攔截器。
    2) 調用getHandlerAdapter來得到第一個supports(handler)trueHandlerAdapter
    DispatcherServlet#getHandlerAdapter(Object handler)

    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");
    }

    3) 然后調用HandlerExecutionChain#applyPreHandle(...)開始應用攔截器,一個一個調用其preHandle方法。
    HandlerExecutionChain#applyPreHandle(HttpServletRequest request, HttpServletResponse response)

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (getInterceptors() != null) {
            for (int i = 0; i < getInterceptors().length; i++) {
                HandlerInterceptor interceptor = getInterceptors()[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }

    4) 接著調用HandlerAdapter.handle(...)得到一個ModelAndView對象,里面封裝了數據對象及具體的View對象。具體實現需要查看HandlerAdapter實現類。例如:RequestMappingHandlerAdapter
    5) 然后調用HandlerExecutionChain#applyPostHandle(...)再次應用攔截器,調用其postHandle方法。
    HandlerExecutionChain#applyPreHandleapplyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv)

    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
        if (getInterceptors() == null) {
            return;
        }
        for (int i = getInterceptors().length - 1; i >= 0; i--) {
            HandlerInterceptor interceptor = getInterceptors()[i];
            interceptor.postHandle(request, response, this.handler, mv);
        }
    }

    6) 最后一步processDispatchResult處理結果,相應給客戶端。在processDispatchResult首先調用了render方法
    DispatcherServlet#processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception)

    render(mv, request, response);

    最后是HandlerExecutionChain#triggerAfterCompletion(...),調用攔截器的afterCompletion方法。攔截器處理流程至此結束。
    分析一下reader方法。首先調用resolveViewName,在里面先遍歷所有的ViewResolver實例,調用其resolveViewName方法,返回第一不為空的View實例。
    DispatcherServlet#resolveViewName(String viewName, Map model, Locale locale, HttpServletRequest request)

    protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
            HttpServletRequest request) throws Exception {
    
        for (ViewResolver viewResolver : this.viewResolvers) {
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
                return view;
            }
        }
        return null;
    }

    ViewResolver#resolveViewName具體可參看InternalResourceViewResolver實現。
    最后調用Viewrender方法。render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)方法的具體實現可參考View實現類JstlView
    JstlView中主要是調用renderMergedOutputModel,首先Model對象數據放置到request中,然后得到一個RequestDispatcher,最后調用其forward方法響應給客戶端。

至此一個請求-響應過程結束。

參考資料

Spring MVC 教程,快速入門,深入分析

跟我學SpringMVC

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!