DispatcherServlet
)中的doDispatch
方法,而後委託給doDispatch
方法進行處理。getHandler
方法,經過HandlerMapping
查找 Handler
(根據配置、註解進行查找)Handler
以後,會把請求封裝成HandlerExecutionChain
對象(包含一個Handler
處理器(頁面控制器)對象,多個HandlerInterceptor
攔截器對象)並返回。getHandlerAdapter
方法獲取支持處理這種handler
的處理器適配器HandlerAdapter
。HandlerAdapter
,將會根據適配的結果去執行Handler,一般會是由RequestMappingHandlerAdapter#handleInternal
進行執行。Handler
執行完成給適配器返回ModelAndView
,這裏Handler
執行的一般是咱們本身編寫的controller
實現。ModelAndView
(ModelAndView
是springmvc框架的一個底層對象,包括 Model和view) DispatcherServlet
是Spring MVC框架的中央處理器,它負責攔截全部請求,並分發到各控制器;同時提供其餘web應用開發所須要的功能。DispatcherServlet
是個Servlet
(它繼承自HttpServlet
基類),不過能作的比這更多。它與Spring IoC容器作到了無縫集成,這意味着,Spring提供的任何特性,在Spring MVC中你均可以使用。前端
DispatcherServlet
使用了特殊的bean來處理請求、渲染視圖等,這些特定的bean是框架的一部分,依賴於這些特殊的bean來進行它的初始化。Spring MVC維護了一個默認的bean列表,若是你沒有進行特別的配置,框架將會使用這些默認的bean。java
DispatcherServlet
細分以後,能夠整理出三個功能:web
組件 Bean 類型 | 說明 |
---|---|
HandlerMapping | 處理器映射。它會根據某些規則將進入容器的請求映射到具體的處理器以及一系列前處理器和後處理器(即處理器攔截器)上。具體的規則視HandlerMapping 類的實現不一樣而有所不一樣。其最經常使用的一個實現支持你在控制器上添加註解,配置請求路徑。固然,也存在其餘的實現。 |
HandlerAdapter | 處理器適配器。拿到請求所對應的處理器後,適配器將負責去調用該處理器,這使得DispatcherServlet 無需關心具體的調用細節。比方說,要調用的是一個基於註解配置的控制器,那麼調用前還須要從許多註解中解析出一些相應的信息。好比,調用註解實現的 Controller 須要解析其關聯的註解. HandlerAdapter 的主要目的是爲了屏蔽與 DispatcherServlet 之間的諸多細節。 |
HandlerExceptionResolver | 處理器異常解析器,它負責將捕獲的異常映射到不一樣的視圖上去,此外還支持更復雜的異常處理代碼。 |
ViewResolver | 視圖解析器,從處理器(Handler)返回字符類型的邏輯視圖名稱解析出實際的 View 對象,該對象將渲染後的內容輸出到HTTP 響應中。 |
MultipartResolver | 解析multi-part的傳輸請求,好比支持經過HTML表單進行的文件上傳等。 |
職責: HandlerMapping
的做用是根據當前請求的找到對應的 Handler
,並將 Handler
(執行程序)與 HandlerInterceptor
(攔截器)封裝到 HandlerExecutionChain
對象(處理程序執行鏈,由處理程序對象和處理程序攔截器組成)中並返回。spring
參與時機: 在請求到達 DispatcherServlet#doDispatch
的時候,會根據當前請求來肯定處理程序,詳細流程以下:json
1,首先調用getHandler
方法,從容器中取出全部 HandlerMapping
接口實例並遍歷,讓 HandlerMapping
接口的實例根據本身實現類的方式去嘗試查找 Handler
。session
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { //...省略 // 查找給定請求的處理程序 HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
2,在 HandlerMapping
接口的內部只有一個方法,從實現類 AbstractHandlerMapping
中的方法能夠看出,會首先根據request獲取到 handler
對象,而後經過request和 handler
來獲取 HandlerExecutionChain
處理程序執行鏈。mvc
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); //...省略 // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } //...省略 // 獲取 處理程序攔截器 HandlerInterceptor並進行組裝, HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); return executionChain; }
3,getHandlerExecutionChain
方法首先會將以前獲取到 handler
裝入 HandlerExecutionChain
中,而後經過遍歷 處理程序攔截器 將符合條件的攔截器添加到 HandlerExecutionChain
處理程序執行鏈中並返回。app
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); //獲取攔截器 String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }
4,最終獲取到HandlerExecutionChain
對象後,交由 HandlerAdapter
(處理器適配器)進行下一步的處理。框架
職責: Spring MVC的handler(Controller
、HttpRequestHandler
等)有多種實現方式,例如繼承Controller
的,基於註解控制器方式的,HttpRequestHandler
方式的。因爲實現方式不同,調用方式就不肯定了。 若是正常編寫調用,就須要使用多個if else判斷instance of,再添加實現方式,就須要修改源碼,不符合對擴展開放,對修改關閉原則,因此Spring MVC提供了處理器適配器(HandlerAdapter
),屏蔽了各類handler的差別,以一種統一的方式進行處理。異步
在HandlerAdapter
中有三個方法,分別是supports
、handle
和getLastModified
,
public interface HandlerAdapter { /** * 判斷是否支持傳入的handler */ boolean supports(Object handler); /** * 使用給定的handler處理請求 */ ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; /** * 返回上次修改時間,能夠返回-1表示不支持 */ long getLastModified(HttpServletRequest request, Object handler); }
HandlerAdapter
是一個接口,有多種實現方式,不過在咱們平時使用中,通常只會用到RequestMappingHandlerAdapter
這種實現,它應該是目前springMVC主要採用的實現,針對方法級的映射匹配處理。
RequestMappingHandlerAdapter
繼承自AbstractHandlerMethodAdapter
抽象類,而AbstractHandlerMethodAdapter
是HandlerAdapter
接口的抽象實現。
繼承關係:HandlerAdapter
-->AbstractHandlerMethodAdapter
-->RequestMappingHandlerAdapter
。
參與時機: 當一個請求被HandlerMapping
處理結束,來處處理器適配器進行處理時:
1,首先調用getHandlerAdapter
方法獲得HandlerAdapter
對象,而後調用handle
方法進行下一步處理。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { //...省略 // 獲取到匹配的 HandlerAdapter 對象 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //...省略 //進行調用 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //...省略 }
2,而後會進入到方法AbstractHandlerMethodAdapter#handle
中,進行調用handleInternal
,這是一個抽象方法
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); }
3,此時會調用實現類RequestMappingHandlerAdapter
中的handleInternal
方法實現,
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { //...省略 if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { mav = invokeHandlerMethod(request, response, handlerMethod); } //...省略 return mav; }
4,調用invokeHandlerMethod
方法,它會調用咱們本身編寫Controller
中的RequestMapping
方法邏輯,以及其餘配置進行處理
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); //設置參數處理器 if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } //設置返回值理器 if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); 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); } // 調用並進行處理 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } // 返回值ModelAndView處理 return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }
5,執行ServletInvocableHandlerMethod#invokeAndHandle
方法,調用並進行處理
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //1.處理調用Controller中的具體方法 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 2.設置返回狀態碼 setResponseStatus(webRequest); //3.當前請求無返回值或者返回值中包含錯誤,則將請求完成標識設置爲true並返回 if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; } // 4.當前請求有返回值且無錯誤信息,則將請求完成標識設置爲false,並繼續處理當前請求 mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null, "No return value handlers"); try { this.returnValueHandlers.handleReturnValue( //// 選取合適的HandlerMethodReturnValueHandler,並處理返回值 returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } }
其中最重要的就是第一步invokeForRequest
方法:
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { /** * 注意這裏不必定都是解析@RequestMapping方法的參數, * 也有可能會解析@InitBinder方法的參數 * * 因此下面的doInvoke方法也並不必定調用具體的@RequestMapping方法, * 也有可能調用@InitBinder方法進行參數的解析綁定 */ // 獲取並解析請求參數 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } // 調用系統反射方法進行執行 return doInvoke(args); }
職責: 在處理適配器處理完請求後,就會到視圖解析器(ViewResolver)進行下一步的處理,Spring MVC中全部控制器的處理器方法都必須返回一個邏輯視圖的名字,不管是顯式返回(好比返回一個String
、View
或者對象)仍是隱式返回(好比基於約定的返回)。Spring中的視圖由一個視圖名標識,並由視圖解析器來渲染。
其他待補充
職責: 能夠配置處理器攔截器HandlerInterceptors
或web請求攔截器WebRequestInterceptors
等攔截器,並配置它們攔截全部進入容器的請求,或限定到符合特定模式的URL路徑。這個沒什麼能夠說的,你們也都熟,咱們對Spring MVC進行功能擴展時常常會用到它。
參與時機: 在處理器映射進行Handle
裝配的時候,會把攔截器給組裝成列表,而後在 處理器適配器 進行處理的時候,會按照設置對攔截器進行執行,請求到來攔截器的執行在下述REST相關組件
以前,返回處理在下述REST相關組件
以後。
使用方法: 見 對SpringMVC進行擴展 中的介紹
職責: 對出現異常的請求進行處理,這個我們公司已經使用了統一異常攔截方式( @controlleradvice
+@ExceptionHandler
),對這個已經再也不使用,沒有介紹的必要。
參與時機: 當請求出現異常時。
使用方法: 略
職責: 本身編寫的controller就是處理請求的處理器,這個不須要介紹,你們每天用。
參與時機: 在處理器適配器進行時,會匹配到咱們本身編寫的請求處理器,進行處理。
使用方法: 本身編寫,使用@Controller
和@xxxMapping
等註解進行聲明。
待補充
職責: 用於 HTTP 請求中解析 HandlerMethod
參數內容,處理成Handler
可用的參數數據,
參與時機: 在請求到來,進行到要對進行參數處理的時候,就會在方法參數解析器列表查找匹配的處理器,對參數進行處理。
使用方法: 見 對SpringMVC進行擴展 中的介紹
職責: 用於 HandlerMethod
返回值解析爲 HTTP 響應內容
參與時機: 當方法處理完畢後,獲得返回值以後,就會在方法返回值解析器列表中查找匹配的處理器,針對返回值進行處理。
使用方法: 見 對SpringMVC進行擴展 中的介紹
職責: HTTP 消息轉換器,用於反序列化 HTTP 請求或序列化響應。這個組件是方法級別的,
參與時機: 在請求到來時和處理完畢進行返回的時候,能夠數據進行轉換和處理,對請求數據進行處理的時機在 處理方法參數解析器
以前,對返回值進行處理時在方法返回值解析器
以前。
使用方法: 見 對SpringMVC進行擴展 中的介紹
註解 | 說明 | Spring Framework 版本 |
---|---|---|
@RestController | 等效於 @Controller + @ResponseBody |
4.0 + |
@RequestMapping | 應用控制器映射註解聲明 | 2.5+ |
@xxxMapping | 等效於 @RequestMapping(method =RequestMethod.XXX) |
4.3+ |
@RequestParam | 獲取請求參數 | 2.5+ |
@RequestHeader | 獲取請求頭 | 3.0+ |
@PathVariable | 獲取請求路徑變量 | 3.0+ |
@RequestBody | 獲取完整請求主體內容 | 3.0+ |
@ResponseBody | 響應主體聲明 | 2.5+ |
@PostConstruct | 會在依賴注入完成後被自動調用 | JavaEE註解 |