日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

概述 :

 

DispatcherServlet作為Spring MVC的核心控制器,初始化組件,處理客戶端發(fā)送的請求,并返回 ModelAndView,進(jìn)行視圖渲染。主要是實現(xiàn)了父類 FrameworkServlet的抽象方法 doService()。

 

DispatcherServlet 類圖

Spring MVC 核心調(diào)用流程

 

DispatcherServlet的 initStrategies方法如何被調(diào)用的

入口類:AbstractApplicationContext # refresh

├─ refresh

│├─ finishRefresh

││└─ publishEvent

│││├─ publishEvent

│││└─ multicastEvent

││││└─ invokeListener

│││││└─ doInvokeListener

││││││└─ onApplicationEvent

│││││││└─ onRefresh

││││││││└─ onRefresh

│││││││││└─ initStrategies

進(jìn)入 onRefresh方法

所在類:org.springframework.web.servlet. DispatcherServlet

    protected void onRefresh(ApplicationContext context) {        initStrategies(context);    }    protected void initStrategies(ApplicationContext context) {        // 初始化文件上傳處理        initMultipartResolver(context);        // 初始化本地化 Resolver        initLocaleResolver(context);        // 初始化主題 Resolver        initThemeResolver(context);        // 初始化 URL映射關(guān)系        initHandlerMappings(context);        // 初始化Handler接口適配器        initHandlerAdapters(context);        // 初始化異常處理的 handler        initHandlerExceptionResolvers(context);        // 初始化請求路徑轉(zhuǎn)換        initRequestToViewNameTranslator(context);        // 初始化視圖解析        initViewResolvers(context);        // 初始化 flashmap管理        initFlashMapManager(context);    }

::: warning 知識點 initStrategies方法中的所有初始化組件中之所以可以拿到值,主要是通過 @EnableWebMvc注解,調(diào)用到 WebMvcConfigurationSupport類中的各個 @Bean注解的方法,完成的實例化過程。:::

請求調(diào)用流程

當(dāng)父子容器都啟動完成后,開始進(jìn)行請求的響應(yīng)處理,

  • 請求 http://localhost:9090/user/queryUser地址

進(jìn)入 service方法

所在類:JAVAx.servlet.http. HttpServlet

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        String method = req.getMethod();        long lastModified;        if (method.equals("GET")) {            lastModified = this.getLastModified(req);            if (lastModified == -1L) {                this.doGet(req, resp);            }           // ...... 省略    }

進(jìn)入 doGet方法

所在類:org.springframework.web.servlet. FrameworkServlet

@Override    protected final void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        processRequest(request, response);    }

進(jìn)入 processRequest方法

所在類:org.springframework.web.servlet. FrameworkServlet

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        long startTime = System.currentTimeMillis();        Throwable failureCause = null;        doService(request, response);}

進(jìn)入 doService方法

所在類:org.springframework.web.servlet. DispatcherServlet

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {        logRequest(request);        try {            // 調(diào)用核心流程            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);                }            }        }}

請求調(diào)用 核心入口

請求最終進(jìn)入 doDispatch方法

所在類:org.springframework.web.servlet. DispatcherServlet

    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將通過                // MultipartResolver進(jìn)行文件上傳解析                processedRequest = checkMultipart(request);                multipartRequestParsed = (processedRequest != request);                // 對當(dāng)前請求匹配一個合適的 handler,重要方法                mappedHandler = getHandler(processedRequest);                if (mappedHandler == null) {                    noHandlerFound(processedRequest, response);                    return;                }                // Determine handler adapter for the current request.                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());                // Process last-modified header, if supported by the handler.                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;                }                // Actually invoke the handler.                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());                if (asyncManager.isConcurrentHandlingStarted()) {                    return;                }                applyDefaultViewName(processedRequest, mv);                mappedHandler.applyPostHandle(processedRequest, response, mv);            }            catch (Exception ex) {                dispatchException = ex;            }            catch (Throwable err) {                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 {                // 如果是multipart的請求,清空上傳的multipart資源                if (multipartRequestParsed) {                    cleanupMultipart(processedRequest);                }            }        }    }

::: warning 知識點總結(jié), getHandler方法的主要作用體現(xiàn)在以下幾點:

  • 首先,從當(dāng)前Request中拿到請求的 URL
  • 然后,從映射關(guān)系中拿到 HandlerMethod對象
  • 接著,把 HandlerMethod對象封裝到 HandlerExecutionChain執(zhí)行鏈中
  • 最后,在 HandlerExecutionChain執(zhí)行鏈的創(chuàng)建過程中會拿到整個容器中所有的攔截器(實現(xiàn) HandlerInterceptor接口的攔截器),和當(dāng)前請求的 URL進(jìn)行匹配,如果匹配成功的話,就會把攔截器放到 HandlerExecutionChain的數(shù)組中。:::

進(jìn)入 getHandler方法

所在類:org.springframework.web.servlet. DispatcherServlet

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {        // handlerMappering 實例容器不為空        if (this.handlerMappings != null) {            for (HandlerMapping mapping : this.handlerMappings) {                // 獲取 HandlerMethod 和過濾器鏈的包裝類                HandlerExecutionChain handler = mapping.getHandler(request);                if (handler != null) {                    return handler;                }            }        }        return null;    }

進(jìn)入 getHandler方法

所在類:org.springframework.web.servlet.handler. AbstractHandlerMapping

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {        // 根據(jù)請求的 URL 拿到對應(yīng)的 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 = obtainApplicationContext().getBean(handlerName);        }        // 獲取 HandlerMethod 和過濾器鏈的包裝類        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);        if (logger.isTraceEnabled()) {            logger.trace("Mapped to " + handler);        }        else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {            logger.debug("Mapped to " + executionChain.getHandler());        }        // 是否是跨域請求,就是查看 request 請求頭中是否有 Origin 屬性        if (CorsUtils.isCorsRequest(request)) {            CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);            CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);            CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);            executionChain = getCorsHandlerExecutionChain(request, executionChain, config);        }        return executionChain;    }

進(jìn)入 getHandlerInternal方法

所在類:org.springframework.web.servlet.handler. AbstractHandlerMethodMapping

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {        // 從request對象中獲取 URL,/common/query2        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);        this.mappingRegistry.acquireReadLock();        try {            // 根據(jù) URL 從映射關(guān)系中找到對應(yīng)的 HandlerMethod 對象            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);            // 執(zhí)行beanFactory.getBean的過程,獲取Controller實例            return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);        }        finally {            this.mappingRegistry.releaseReadLock();        }    }

::: warning 知識點

lookupHandlerMethod方法之所以可以從映射關(guān)系中拿到 HandlerMethod對象,是因為 AbstractHandlerMethodMapping類實現(xiàn)了 InitializingBean接口,在 afterPropertiesSet方法里建立好了映射關(guān)系。:::

進(jìn)入 lookupHandlerMethod方法

所在類:org.springframework.web.servlet.handler. AbstractHandlerMethodMapping

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {        List<Match> matches = new ArrayList<>();        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);        if (directPathMatches != null) {            // 匹配過程,是否符合 RequestMappingInfo 里的屬性值            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));            matches.sort(comparator);            Match bestMatch = matches.get(0);            if (matches.size() > 1) {                if (logger.isTraceEnabled()) {                    logger.trace(matches.size() + " matching mappings: " + matches);                }                if (CorsUtils.isPreFlightRequest(request)) {                    return PREFLIGHT_AMBIGUOUS_MATCH;                }                Match secondBestMatch = matches.get(1);                // 如果兩個 RequestMappinginfo 什么都相同,報錯                if (comparator.compare(bestMatch, secondBestMatch) == 0) {                    Method m1 = bestMatch.handlerMethod.getMethod();                    Method m2 = secondBestMatch.handlerMethod.getMethod();                    String uri = request.getRequestURI();                    throw new IllegalStateException(                            "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");                }            }            request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);            handleMatch(bestMatch.mapping, lookupPath, request);            return bestMatch.handlerMethod;        }        else {            return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);        }    }

::: warning 知識點

addMatchingMappings方法,主要一個匹配過程,匹配 @RequestMapping注解中的屬性值是否滿足

 /*  * consumes:指定處理請求的提交內(nèi)容類型(Content-Type),  *     例如application/json, text/html;  * produces: 指定返回的內(nèi)容類型,僅當(dāng)request請求頭中的(Accept)類型中包含該指定類型才返回;  * params:指定request中必須包含某些參數(shù)值是,才讓該方法處理。  * headers:指定request中必須包含某些指定的header值,才能讓該方法處理請求。  * */@RequestMapping(value = "/getUser",    method = RequestMethod.GET,    params = "username=jack",    consumes = "application/json",    produces = "application/json",    headers = "Referer=http://www.xx.com/")

:::

返回 getHandler,進(jìn)入 getHandlerExecutionChain方法

所在類:org.springframework.web.servlet.handler. AbstractHandlerMapping

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {        // 如果沒有獲得則創(chuàng)建一個 HandlerExecutionChain        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));        // 獲取當(dāng)前的請求地址:/user/xxx        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);        // 在 HandlerExecutionChain 中添加攔截器        // 遍歷 SpringMVC 容器的所有攔截器        for (HandlerInterceptor interceptor : this.adaptedInterceptors) {            // 判斷攔截器類型,如果是 MappedInterceptor 類型            if (interceptor instanceof MappedInterceptor) {                MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;                // 則先匹配路徑后再添加到執(zhí)行鏈                if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {                    chain.addInterceptor(mappedInterceptor.getInterceptor());                }            }            else {                // 否則直接添加到執(zhí)行鏈                chain.addInterceptor(interceptor);            }        }        return chain;    }

::: warning 知識點

getHandlerExecutionChain中的 HandlerInterceptor攔截器是 SpringMVC中的, SpringAOP中的攔截器是 MethodInterceptor。:::

拿到當(dāng)前請求對應(yīng)的 handler后,

返回主流程,進(jìn)入 getHandlerAdapter方法

所在類:org.springframework.web.servlet. DispatcherServlet

/** * TODO : 根據(jù) handlerMethod對象,找到合適的 HandlerAdapter對象,這里用到了策略模式 */protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {        if (this.handlerAdapters != null) {            for (HandlerAdapter adapter : this.handlerAdapters) {                if (adapter.supports(handler)) {                    // 返回一個可以支持的HandlerAdapter 處理程序?qū)嵗?                   return adapter;                }            }        }        throw new ServletException("No adapter for handler [" + handler +                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");    }

::: warning 知識點

HandlerAdapter 是什么HandlerAdapter是一個接口,充當(dāng)自身與處理程序?qū)ο笾g的橋梁,從而導(dǎo)致松散耦合設(shè)計。HandlerAdapter主要處理方法參數(shù)、相關(guān)注解、數(shù)據(jù)綁定、消息轉(zhuǎn)換、返回值、調(diào)用視圖解析器等。

RequestMappingHandlerMapping為當(dāng)前的請求找到合適的處理程序方法。

RequestMappingHandlerAdapter執(zhí)行這個處理程序方法,并為它提供反射調(diào)用所需要的參數(shù)。

 

HandlerAdapter UML 圖

HandlerAdapter的4個實現(xiàn)類:

SimpleServletHandlerAdapter: 適配實現(xiàn) Servlet 接口的 Handler, 默認(rèn)調(diào)用其 service方法

SimpleControllerHandlerAdapter: 適配實現(xiàn) Controller 接口的 Handler, 默認(rèn)調(diào)用其 handleRequest 方法

HttpRequestHandlerAdapter: 適配實現(xiàn) HttpRequestHandler 接口的 Handler, 默認(rèn)調(diào)用其 handleRequest 方法

RequestMappingHandlerAdapter: 適配被 @RequestMapping注釋的方式, 一般都是解析一個一個參數(shù), 并且通過反射進(jìn)行激活

HandlerAdapter 總結(jié)HandlerAdapter 是 SpringMVC中擴(kuò)展機(jī)制的非常好的一個體現(xiàn),,通過 HandlerAdapter這種設(shè)計模式, DispatcherServlet 就可以支持任何格式的 Handler(這里的可以支持指在不改變 DispatcherServlet 的情況下),第二是 HandlerAdapter 基于不同 Handler實現(xiàn)不同實現(xiàn)類(策略模式),最后也是最重要的就是參數(shù)的解析與返回值的解析。

:::

::: danger 為什么要用HandlerAdapter適配器模式? 首先, Controller的定義有多種 ,一種是帶 @Controller注解的, 還可以寫一個 servlet 當(dāng)做 controller, 所以用適配器做適配,不同子類實現(xiàn) HandlerAdapter接口,定義自己的業(yè)務(wù)邏輯,每個子類都是適配某一種類型的控制器,有了 HandlerAdapter,你只需要調(diào)用自己實現(xiàn)的 handle方法,屏蔽了不一致的細(xì)節(jié),對用戶來說直接找到對應(yīng)的處理方法,無須關(guān)系哪個實現(xiàn)方法,否則只能在 DispatcherServlet里面通過 if、 else來處理了。:::

前置過濾器

返回主流程,進(jìn)入 applyPreHandle方法,前置過濾器

所在類:org.springframework.web.servlet. DispatcherServlet

/** * TODO :調(diào)用所有的 HandlerInterceptor 攔截器并調(diào)用其 preHandler方法 */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];                // 分別調(diào)用攔截器的 preHandle 方法                if (!interceptor.preHandle(request, response, this.handler)) {                    triggerAfterCompletion(request, response, null);                    return false;                }                // 如果失敗,記錄最后一次攔截器的位置,倒序釋放                this.interceptorIndex = i;            }        }        return true;    }

返回主流程,進(jìn)入 handle方法,調(diào)用具體 Controller的方法

最終會進(jìn)入 AbstractHandlerMethodAdapter的 handle方法,

    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)            throws Exception {        return handleInternal(request, response, (HandlerMethod) handler);    }

進(jìn)入 handleInternal方法,

所在類:org.springframework.web.servlet.mvc.method.annotation. RequestMappingHandlerAdapter

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                // 執(zhí)行 HandlerMethod,返回 ModelAndView                mav = invokeHandlerMethod(request, response, handlerMethod);            }        }        else {            // No synchronization on session demanded at all...            // 執(zhí)行 HandlerMethod,返回 ModelAndView            mav = invokeHandlerMethod(request, response, handlerMethod);        }        if (!response.containsHeader(HEADER_CACHE_CONTROL)) {            if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {                applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);            }            else {                prepareResponse(response);            }        }        return mav;    }

進(jìn)入 invokeHandlerMethod方法,

所在類:org.springframework.web.servlet.mvc.method.annotation. RequestMappingHandlerAdapter

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {        ServletWebRequest webRequest = new ServletWebRequest(request, response);        try {            // 獲取數(shù)據(jù)綁定工廠  @InitBinder注解支持,            WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);            // Model工廠,收集了@ModelAttribute注解的方法            ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);            //可調(diào)用的方法對象            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);            if (this.argumentResolvers != null) {                //設(shè)置參數(shù)解析器                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);            }            if (this.returnValueHandlers != null) {                // 設(shè)置返回值解析器                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);            }            // 設(shè)置參數(shù)綁定工廠            invocableMethod.setDataBinderFactory(binderFactory);            // 設(shè)置參數(shù)名稱解析類            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);            ModelAndViewContainer mavContainer = new ModelAndViewContainer();            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));            // 調(diào)用有 @ModelAttribute注解的方法。每次請求都會調(diào)用有 @ModelAttribute注解的方法            //把 @ModelAttribute注解的方法的返回值存儲到 ModelAndViewContainer對象的 map中了            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();                LogFormatUtils.traceDebug(logger, traceOn -> {                    String formatted = LogFormatUtils.formatValue(result, !traceOn);                    return "Resume with async result [" + formatted + "]";                });                invocableMethod = invocableMethod.wrapConcurrentResult(result);            }            // Controller方法調(diào)用,重點看看            invocableMethod.invokeAndHandle(webRequest, mavContainer);            if (asyncManager.isConcurrentHandlingStarted()) {                return null;            }            return getModelAndView(mavContainer, modelFactory, webRequest);        }        finally {            webRequest.requestCompleted();        }    }

::: warning 知識點

invokeHandlerMethod方法主要進(jìn)行了數(shù)據(jù)和參數(shù)的綁定、創(chuàng)建 ModelAndViewContainer視圖容器,以及相關(guān)初始化工作。:::

進(jìn)入 invokeAndHandle方法

所在類:org.springframework.web.servlet.mvc.method.annotation. ServletInvocableHandlerMethod

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,            Object... providedArgs) throws Exception {        // 具體調(diào)用邏輯,重點看        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);        Assert.state(this.returnValueHandlers != null, "No return value handlers");        try {            // 返回值處理            this.returnValueHandlers.handleReturnValue(                    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);        }        catch (Exception ex) {            if (logger.isTraceEnabled()) {                logger.trace(formatErrorForReturnValue(returnValue), ex);            }            throw ex;        }    }

進(jìn)入 invokeForRequest方法

所在類:org.springframework.web.method.support. InvocableHandlerMethod

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,            Object... providedArgs) throws Exception {        // 獲取參數(shù)數(shù)組,重點看        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);        if (logger.isTraceEnabled()) {            logger.trace("Arguments: " + Arrays.toString(args));        }        return doInvoke(args);    }

進(jìn)入 getMethodArgumentValues方法

所在類:org.springframework.web.method.support. InvocableHandlerMethod

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,            Object... providedArgs) throws Exception {        if (ObjectUtils.isEmpty(getMethodParameters())) {            return EMPTY_ARGS;        }        // 入?yún)⒌陌b類,里面包裝了參數(shù)類型,參數(shù)名稱,參數(shù)注解等等信息        MethodParameter[] parameters = getMethodParameters();        Object[] args = new Object[parameters.length];        for (int i = 0; i < parameters.length; i++) {            MethodParameter parameter = parameters[i];            // 設(shè)置參數(shù)名稱解析器            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);            args[i] = findProvidedArgument(parameter, providedArgs);            if (args[i] != null) {                continue;            }            // 典型的策略模式,根據(jù) parameter 能否找到對應(yīng)參數(shù)的處理類,能找到就返回true            if (!this.resolvers.supportsParameter(parameter)) {                throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));            }            try {                // 具體參數(shù)值解析過程,重點看看                args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);            }            catch (Exception ex) {                // Leave stack trace for later, exception may actually be resolved and handled..                if (logger.isDebugEnabled()) {                    String error = ex.getMessage();                    if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {                        logger.debug(formatArgumentError(parameter, error));                    }                }                throw ex;            }        }        return args;    }

進(jìn)入 resolveArgument方法

所在類:org.springframework.web.method.support. HandlerMethodArgumentResolverComposite

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {        // 根據(jù)參數(shù)獲取對應(yīng)參數(shù)的解析類        HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);        if (resolver == null) {            throw new IllegalArgumentException(                    "Unsupported parameter type [" + parameter.getParameterType().getName() + "]." +                            " supportsParameter should be called first.");        }        // 策略模式去調(diào)用具體參數(shù)解析類        return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);    }

::: warning 知識點

MethodParameter類是對參數(shù)信息的封裝,其中重要的幾個屬性包括:

  • parameterIndex:參數(shù)的索引位置
  • Parameter:具體參數(shù)的對象,包含參數(shù)名字
  • parameterType:參數(shù)的類型
  • parameterAnnotations:參數(shù)的注解數(shù)組,一個參數(shù)可以有多個注解
  • parameterName:參數(shù)名 等等 :::

方法參數(shù)解析

進(jìn)入 getArgumentResolver方法

所在類:org.springframework.web.method.support. HandlerMethodArgumentResolverComposite

private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {        // 先從緩存中拿到參數(shù)處理器對象        HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);        // 如果緩存中沒有        if (result == null) {            // 循環(huán)容器中 HandlerMethodArgumentResolver類型的所有解析器: List<HandlerMethodArgumentResolver>            for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {                // 典型的策略模式匹配,拿到當(dāng)前參數(shù)對應(yīng)的處理解析類                if (methodArgumentResolver.supportsParameter(parameter)) {                    // 賦值給 HandlerMethodArgumentResolver 對象                    result = methodArgumentResolver;                    // 放到緩存中                    this.argumentResolverCache.put(parameter, result);                    break;                }            }        }        return result;    }

::: warning 知識點

HandlerMethodArgumentResolver參數(shù)解析器,最復(fù)雜的處理流程之一,Spring中默認(rèn)有26種參數(shù)解析器,來對應(yīng)完成某種參數(shù)的解析工作。添加過程是 SpringMVC啟動實例化后,通過 RequestMappingHandlerAdapter類的 afterPropertiesSet方法調(diào)用 getDefaultArgumentResolvers添加到 HandlerMethodArgumentResolver解析器中的。:::

中置過濾器

返回主流程,進(jìn)入 handleInternal方法,中置過濾器

所在類:org.springframework.web.servlet.mvc.method.annotation. RequestMappingHandlerAdapter

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)            throws Exception {        // 獲取所有攔截器        HandlerInterceptor[] interceptors = getInterceptors();        if (!ObjectUtils.isEmpty(interceptors)) {            for (int i = interceptors.length - 1; i >= 0; i--) {                HandlerInterceptor interceptor = interceptors[i];                // 分別調(diào)用攔截器的 postHandle方法                interceptor.postHandle(request, response, this.handler, mv);            }        }    }

::: warning 知識點中置過濾器的調(diào)用時序,是當(dāng) ha.handle 掉完以后,也就是 Controller 里面具體方法調(diào)用完以后才輪到中置過濾器調(diào)用。可以根據(jù) ModelAndView對象做視圖修改。:::

后置過濾器

返回主流程,進(jìn)入 triggerAfterCompletion方法,后置過濾器

所在類:org.springframework.web.servlet.mvc.method.annotation. RequestMappingHandlerAdapter

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable 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);                }            }        }    }

::: warning 知識點

applyPreHandle前置過濾器主要作用是對當(dāng)前請求做一些初步的驗證,內(nèi)部執(zhí)行順序是正序遍歷, applyPostHandle 中置過濾器和 triggerAfterCompletion后置過濾器的執(zhí)行順序是倒序遍歷,倒序是因為一但前置過濾器中斷(攔截器 preHndle返回 false)那么請求終止,根據(jù)中斷的數(shù)組坐標(biāo) interceptorIndex,倒序釋放執(zhí)行已經(jīng)過濾的的攔截方法。:::

到此為止,主流程結(jié)束,以上完成了Spring MVC`從請求到處理的一系列過程,包括請求方法調(diào)用

、參數(shù)解析、過濾器調(diào)用等,接下來就是處理返回值的解析工作。

附:常見注解

::: danger 常見注解

  • @ModelAttribute:會在調(diào)用Controller的每個方法執(zhí)行前被執(zhí)行。
  • @RequestBody:用來處理 content-type為 application/json的類型,可以是對象。
  • @ResponseBody:一般用于返回 JSON 或 XML 數(shù)據(jù)。
  • @RequestPart:用來處理 content-type為 multipart/form-data類型的表單提交請求。
  • @ExceptionHandler:用在方法上,在運行時有效,只捕獲當(dāng)前Controller 中發(fā)生的異常。
  • @ControllerAdvice:用在類上,@ControllerAdvice("com.xx.xx")只對這個包里 面的 Controller 生效,并將該類中所有使用了 @ExceptionHandler 注解的方法都應(yīng)用到請求處理方法上。
  • @Cacheable:若該緩存中沒有存儲該條記錄,則執(zhí)行該方法,有則從緩存取。
  • @CacheEvict:將該緩存下的所有記錄都清空。
  • @CachePut:總是會執(zhí)行該方法,每次都把返回結(jié)果更新進(jìn)該緩存中。
  • @RequestParam:適用于所有類型的參數(shù);
  • @RequestHeader:用于將請求頭的信息數(shù)據(jù)映射到方法參數(shù)上 。
  • @CookieValue:用于將請求的 cookie 數(shù)據(jù)映射到功能處理方法的參數(shù)上。
  • @InitBinder:用于綁定表單數(shù)據(jù)的注解。
  • @RequestAttribute:用于獲取 request作用域 中的數(shù)據(jù)。
  • @SessionAttribute:用于獲取 session作用域中的數(shù)據(jù)。
  • @PathVariable:獲取請求 URL 中的動態(tài)參數(shù)(路徑參數(shù)),如:"/test4/{id}/{name}"。
  • @MatrixVariable:擴(kuò)展了URL請求地址,多個請求參數(shù)可用 ,分開, 一般用于進(jìn)行多條件的組合查詢。
  • @CrossOrigin:用于不同域名訪問,解決跨域問題。

分享到:
標(biāo)簽:Spring MVC
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達(dá)人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定