淺談SpringMVC請(qǐng)求映射handler源碼解讀
請(qǐng)求映射源碼
首先看一張請(qǐng)求完整流轉(zhuǎn)圖(這里感謝博客園上這位大神的圖,博客地址我忘記了):

前臺(tái)發(fā)送給后臺(tái)的訪問(wèn)請(qǐng)求是如何找到對(duì)應(yīng)的控制器映射并執(zhí)行后續(xù)的后臺(tái)操作呢,其核心為DispatcherServlet.java與HandlerMapper。在spring boot初始化的時(shí)候,將會(huì)加載所有的請(qǐng)求與對(duì)應(yīng)的處理器映射為HandlerMapper組件。我們可以在springMVC的自動(dòng)配置類(lèi)中找到對(duì)應(yīng)的Bean。
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
// Must be @Primary for MvcUriComponentsBuilder to work
return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
resourceUrlProvider);
}
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
請(qǐng)求將首先執(zhí)行FrameworkServlet下的service方法根據(jù)request請(qǐng)求的method找到對(duì)應(yīng)的do**方法。
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
//父類(lèi)根據(jù)method參數(shù)執(zhí)行doGet,doPost,doDelete等
super.service(request, response);
}
}
而這些do**其都會(huì)進(jìn)入核心方法,以doGet為例。
@Overrideprotected
final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//核心方法
processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
//進(jìn)入此核心方法
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
processRequest()方法中重點(diǎn)在doService(request, response);,而其核心處理邏輯位于DispatchServletl類(lèi)重寫(xiě)的方法,如下。
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
····
try {
//這里為實(shí)際分發(fā)控制器的邏輯,其內(nèi)部是找到對(duì)應(yīng)的handlerMapper
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);
}
}
if (requestPath != null) {
ServletRequestPathUtils.clearParsedRequestPath(request);
}
}
}
接下來(lái)看分發(fā)處理邏輯方法,其中重要的方法都使用了原生的注釋。接下來(lái)分別分析核心源碼。
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 {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
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) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
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 {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
首先是分析getHandler(),找到對(duì)應(yīng)的處理器映射邏輯。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
我們將斷點(diǎn)標(biāo)記在getHandler方法上時(shí),可以清除看到handlerMappings,如圖。

這里,用戶請(qǐng)求與處理器的映射關(guān)系都在RequestMapperHandlerMapping中,而歡迎頁(yè)處理請(qǐng)求則在WelcomePageHanderMapping中進(jìn)行映射。
以下為RequestMapperHandlerMapping中映射部分截圖,可以看到用戶的所有請(qǐng)求映射這里面都有:

getHandler()后的方法是通過(guò)比較request請(qǐng)求中method與HandlerMapper中相同url下的method,再進(jìn)行唯一性校驗(yàn),不通過(guò)異常,通過(guò)找到唯一的handler。
后續(xù),通過(guò)handler找到處理的設(shè)配器,通過(guò)適配器得到一個(gè)ModelAndView對(duì)象,這個(gè)對(duì)象就是最后返回給前端頁(yè)面的對(duì)象。
至此,一個(gè)請(qǐng)求完整映射到返回前端結(jié)束。
說(shuō)明:這是實(shí)現(xiàn)了FramworkServlet的doService方法,F(xiàn)ramworkServlet繼承自HttpServlet,并且重寫(xiě)了父類(lèi)中的doGet(),doPost(),doPut(),doDelete 等方法,在這些重寫(xiě)的方法里都調(diào)用了 processRquest() 方法做請(qǐng)求處理,進(jìn)入processRquest()可以看到里面調(diào)用了FramworkServlet中定義的doService() 方法。
到此這篇關(guān)于淺談SpringMVC請(qǐng)求映射handler源碼解讀的文章就介紹到這了,更多相關(guān)SpringMVC請(qǐng)求映射handler 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Spring注解@Autowired的實(shí)現(xiàn)原理和使用方法
在使用Spring開(kāi)發(fā)的時(shí)候,配置的方式主要有兩種,一種是xml的方式,另外一種是 java config的方式,在使用的過(guò)程中,我們使用最多的注解應(yīng)該就是@Autowired注解了,所以本文就給大家講講@Autowired注解是如何使用和實(shí)現(xiàn)的,需要的朋友可以參考下2023-07-07
Spring5新功能@Nullable注解及函數(shù)式注冊(cè)對(duì)象
這篇文章主要為大家介紹了Spring5新功能詳解@Nullable注解及函數(shù)式注冊(cè)對(duì)象,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
Windows安裝Maven并配置環(huán)境的詳細(xì)步驟
Maven是一個(gè)非常流行的構(gòu)建和項(xiàng)目管理工具,用于Java開(kāi)發(fā),它提供了一個(gè)強(qiáng)大的依賴(lài)管理系統(tǒng)和一系列標(biāo)準(zhǔn)化的構(gòu)建生命周期,本文將指導(dǎo)您如何在Windows操作系統(tǒng)上安裝和配置Maven,需要的朋友可以參考下2023-05-05
springboot vue組件開(kāi)發(fā)實(shí)現(xiàn)接口斷言功能
這篇文章主要為大家介紹了springboot+vue組件開(kāi)發(fā)實(shí)現(xiàn)接口斷言功能,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05

