由DispatcherServlet看spring mvc請求處理過程

DispatcherServlet來看spring mvc請求處理過程

架構

官方架構圖
前端控制器模式
能夠看到請求處理過程,而DispatcherServlet正是擔當front controller的角色。前端

生命週期

經過源碼能夠看到,DispatcherServlet繼承自FrameworkServlet,FrameworkServlet繼承HttpServletBean,HttpServletBean繼承HttpServlet。
而Servlet生命週期的三個階段就是【init-service-destroy】
因此對DispatcherServlet而言,相似最初進行servlet編程。繼承HttpServlet,重寫doGet、doPost,在方法中跳轉到jsp頁面,利用註解或者在xml文件中註冊Servlet。web

初始化

在HttpServletBean中,覆寫了HttpServlet類的init()方法。
前面是將web.xml中在DispatcherServlet這個Servlet下面的<init-param>配置元素利用JavaBean的方式(即經過setter方法)讀取到DispatcherServlet中來
值得一提的是其中有一句spring

initServletBean();

可是在HttpServletBean中是一個空方法,留給子類來實現,這就是模版方法,在父類中定義執行流程,把可變的部分留給子類實現。體現了開閉原則。編程

initServletBean在FrameworkServlet中關鍵的一句安全

this.webApplicationContext = initWebApplicationContext();

因此FrameworkServlet存在的意義也用來抽離出創建 WebApplicationContext 上下文這個過程的。創建一個和Servlet關聯的Spring容器上下文,並將其註冊到ServletContext中。數據結構

由於DispatcherServlet重寫了onRefresh,創建上下文後,經過onRefresh(ApplicationContext context)方法的回調,進入到DispatcherServlet類
onRefresh方法中initStrategies()封裝了初始化策略
以detectAllHandlerMappings爲例,detectAllHandlerMappings默認爲true,把上下文中全部HandlerMapping類型的Bean都註冊在handlerMappings這個List變量中。架構

總結:HttpServletBean完成的是<init-param>配置元素的依賴注入,FrameworkServlet完成的是容器上下文的創建,DispatcherServlet完成的是SpringMVC具體編程元素的初始化策略。mvc

Service

以Get請求爲例,通過HttpServlet基類中service()方法的委派,請求會被轉發到doGet()方法中。doGet()方法,在DispatcherServlet的父類FrameworkServlet類中被重寫。
封裝了processRequest方法,關鍵就是doService(request, response);
前一部分是將當前請求的Locale對象和屬性,分別設置到LocaleContextHolder和RequestContextHolder這兩個抽象類中的ThreadLocal對象中,也就是分別將這兩個東西和請求線程作了綁定。在doService()處理結束後,再恢復回請求前的LocaleContextHolder和RequestContextHolder,也即解除線程綁定。每次請求處理結束後,容器上下文都發布了一個ServletRequestHandledEvent事件,你能夠註冊監聽器來監聽該事件。app

只是作了一些線程安全的隔離。cors

doService又是一個抽象方法。子類實現。實如今DispatcherServlet中
doDispatch(request, response);
幾個requet.setAttribute()方法的調用,將前面在初始化流程中實例化的對象設置到http請求的屬性中,供下一步處理使用,其中有容器的上下文對象、本地化解析器等SpringMVC特有的編程元素。

doDispatch中

mappedHandler = getHandler(processedRequest);得到處理請求的handler,返回HandlerExecutionChain
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());得到處理請求的handler adapter
mappedHandler.applyPreHandle(processedRequest, response執行interceptor的prehandle方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());實際調用handler,返回ModelAndView
applyDefaultViewName(processedRequest, mv);設置view的名字

mappedHandler.applyPostHandle(processedRequest, response, mv);執行intercepter的postHandle方法,
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);發送結果

數據結構

HandlerMapping、HandlerAdapter、View這些接口的設計。
HandlerAdapter:是一個接口。support方法根據類型來判斷該adapter是否支持handler實例,handle方法用給定的handler處理請求;

public interface HandlerAdapter {
    boolean supports(Object handler);

    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    long getLastModified(HttpServletRequest request, Object handler);
}

HandlerMapping接口中:
getHandler獲取請求的handler和全部interceptors,返回HandlerExecutionChain的對象

public interface HandlerMapping {
    String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
    String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
    String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
    //...
    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

View接口:
主要是render方法
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;

HandlerExecutionChain:主要包含 interceptors的list,和一個handle,這裏handler是由Object對象來引用的,沒有綁定任何接口,這裏說明了任何對象均可以做爲最後的處理對象來生成視圖
ModelAndView是處理的結果,主要包含Object引用的view,和ModelMap引用的model。view能夠是view名(String)或者是一個view的實例。ModelMap繼承LinkedHashMap,也就是一個map,放了屬性名和屬性值。

HandlerInterceptor這個接口,定義了攔截器的實現
preHandle,postHandle,afterCompletion就像剛剛在doDispatch中同樣,環繞着hanlder實現,分別在handler執行前,執行後和渲染後執行。

public interface HandlerInterceptor {

    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception;
    void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;
    void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;
}

深刻處理流程

mappedHandler

mappedHandler = getHandler(processedRequest);
能夠看出getHandler方法就是遍歷初始化時已經獲取的handlerMappings,若是找到一個HandlerMapping,getHandler方法返回的不爲null,那麼說明找到了這個mappedHandler,並返回。

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

getHandler的實如今AbstractHandlerMapping類中,根據request找到Handler和Interceptor,組合成HandlerExecutionChain類型並返回

@Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = getHandlerInternal(request);
        if (handler == null) {
            handler = getDefaultHandler();
        }
        if (handler == null) {
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }

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

getHandlerInternal是個接口
AbstractHandlerMethodMapping,AbstractUrlHandlerMapping都實現了它。其中AbstractHandlerMethodMapping更經常使用,註解@RequestMapping的方式就屬於它,它將被註解的Method做爲handler。

protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

lookupHandlerMethod方法來查找url和對應的方法

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);

    this.mappingRegistry.acquireReadLock();
    try {
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

從mappingRegistry中獲取匹配路徑的mapping,並排序獲取最匹配的handlerMethod

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()) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            Collections.sort(matches, comparator);
    
            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 + "}");
                }
            }
            handleMatch(bestMatch.mapping, lookupPath, request);
            return bestMatch.handlerMethod;
        }
        else {
            return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
        }
    }
getHandlerAdapter

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

一樣也是遍歷handlerAdapters中全部的adapter,若是和handler的類型匹配,就返回handlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (ha.supports(handler)) {
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }
applyPreHandle

mappedHandler.applyPreHandle(processedRequest, response依次執行interceptor的prehandle方法,若是又一個攔截器返回false就中止

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];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }
handle

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

這個方法在handlerAdapter的接口中,有幾個實現,AbstractHandlerMethodAdapter,AnnotationMethodHandlerAdapter,,,
SimpleServletHandlerAdapter:handle方法就是調用Servlet的service((Servlet) handler).service(request, response);
SimpleControllerHandlerAdapter:handle方法本質是執行Controller.handleRequest方法return ((Controller) handler).handleRequest(request, response);
HttpRequestHandlerAdapter: ((HttpRequestHandler) handler).handleRequest(request, response);
AbstractHandlerMethodAdapter:是一個抽象類,handle方法調用handleInternal,handleInternal是一個接口,在實現類RequestMappingHandlerAdapter中實現。關鍵的地方在於調用invokeHandlerMethod

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    ModelAndView mav;
    checkRequest(request);
//...
    mav = invokeHandlerMethod(request, response, handlerMethod);
//..
    prepareResponse(response);
//..
    return mav;
}

invokeHandlerMethod就是在執行傳入的handler方法

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,  
    HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {  
    .........  
    //執行Controller中的RequestMapping註釋的方法  
    invocableMethod.invokeAndHandle(webRequest, mavContainer);  
      
    //返回ModelAndView視圖  
    return getModelAndView(mavContainer, modelFactory, webRequest);  
}
applyDefaultViewName

applyDefaultViewName(processedRequest, mv);
很簡單,就是設置一下view

private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
    if (mv != null && !mv.hasView()) {
        mv.setViewName(getDefaultViewName(request));
    }
}
applyPostHandle

同上applyPreHandle,執行攔截器list中的postHandle方法

processDispatchResult

關鍵就是調用render方法,而後執行攔截器列表中的AfterCompletion方法

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
        boolean errorView = false;
        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 (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }

render方法中,關鍵的一步view.render(mv.getModelInternal(), request, response);
這個接口在AbstractView這個抽象類中定義了模版方法

@Override
    public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {


        Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
        prepareResponse(request, response);
        renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
    }

createMergedOutputModel,關鍵是這些putAll方法,把靜態的attribute和動態值方都放進mergedModel中而後返回,能夠看到先put staticAttributes後put model,因此說明動態的值優先級更高可能覆蓋靜態attribute的值

protected Map<String, Object> createMergedOutputModel(Map<String, ?> model, HttpServletRequest request,
        HttpServletResponse response) {
        ...
    Map<String, Object> mergedModel = new LinkedHashMap<String, Object>(size);
    mergedModel.putAll(this.staticAttributes);
    if (pathVars != null) {
        mergedModel.putAll(pathVars);
    }
    if (model != null) {
        mergedModel.putAll(model);
    }
    // Expose RequestContext?
    if (this.requestContextAttribute != null) {
        mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));
    }
    return mergedModel;
}

prepareResponse就是設置response頭

protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {
        if (generatesDownloadContent()) {
            response.setHeader("Pragma", "private");
            response.setHeader("Cache-Control", "private, must-revalidate");
        }
    }

renderMergedOutputModel又是一個接口
protected abstract void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception;

有不少實現,對於jsp,在InternalResourceView類中實現

@Override
    protected void renderMergedOutputModel(    Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    // Expose the model object as request attributes.
        exposeModelAsRequestAttributes(model, request);
        // Expose helpers as request attributes, if any.
        exposeHelpers(request);

        // Determine the path for the request dispatcher.
        String dispatcherPath = prepareForRendering(request, response);

        // Obtain a RequestDispatcher for the target resource (typically a JSP).
        RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);

        // If already included or response already committed, perform include, else forward.
        if (useInclude(request, response)) {
            response.setContentType(getContentType());
            rd.include(request, response);
        }

        else {
            // Note: The forwarded resource is supposed to determine the content type itself.
            rd.forward(request, response);
        }
    }

exposeModelAsRequestAttributes方法就是把model中的值都填到request中

protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {
    for (Map.Entry<String, Object> entry : model.entrySet()) {
        String modelName = entry.getKey();
        Object modelValue = entry.getValue();
        if (modelValue != null) {
            request.setAttribute(modelName, modelValue);
        }
        else {
            request.removeAttribute(modelName);
        }
    }
}

若是response已經提交了,included,不然就執行forward到這裏,請求處理結束。

相關文章
相關標籤/搜索