protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
/**
* 聲明變量 HttpServletRequest HandlerExecutionChain Handler執行鏈包含和最扣執行的Handler
*/
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
//是不是一個多組件請求
boolean multipartRequestParsed = false;
//異步管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
//視圖
ModelAndView mv = null;
//異常
Exception dispatchException = null;
try {
/**
* 1.檢查是否上傳請求
*/
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
/**
* 2.根據processedRequest獲取映射的Handler執行鏈 HandlerExecutionChain
* 有當前請求的Handler和Inteceptor
*/
mappedHandler = getHandler(processedRequest);
getHandler方法
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
/**
* 遍歷handlerMappings 映射器
*/
for (HandlerMapping mapping : this.handlerMappings) {
//根據請求獲取HandlerExecutionChain
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
request中有請求的url
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
/**
* 根據請求獲取Handler
*/
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);
}
/**
* 獲取HandlerExecutionChain
*/
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());
}
/**
* 跨域配置
*/
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;
}
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal方法
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
/**
* 獲取請求的url如 /demo/handler01
*/
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
/**
* 查詢和url reqeust匹配的HandlerMthod
*/
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
//返回
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod方法
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
/**
* 根據URL獲取匹配 ,可以匹配到多個
* 通過uri直接在註冊的RequestMapping中獲取對應的RequestMappingInfo列表,需要注意的是,
* 這裏進行查找的方式只是通過url進行查找,但是具體哪些RequestMappingInfo是匹配的,還需要進一步過濾
*/
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
/**
* 如果匹配的就添到上面的集合中
*/
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// 如果無法通過uri進行直接匹配,則對所有的註冊的RequestMapping進行匹配,這裏無法通過uri
// 匹配的情況主要有三種:
// ①在RequestMapping中定義的是PathVariable,如/user/detail/{id};
// ②在RequestMapping中定義了問號表達式,如/user/?etail;
// ③在RequestMapping中定義了*或**匹配,如/user/detail/**
// 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);
/**
* 會判斷前兩個是否相似度是一樣的,如果是一樣的,則直接拋出異常,如果不相同,
*/
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);
//這裏主要是對匹配結果的一個處理,主要包含對傳入參數和返回的MediaType的處理
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
這裏對於結果的匹配,首先會通過uri進行直接匹配,如果能匹配到,則在匹配結果中嘗試進行RequestMethod,Consumes和Produces等配置的匹配;如果通過uri不能匹配到,則直接對所有定義的RequestMapping進行匹配,這裏主要是進行正則匹配,如果能匹配到。如果能夠匹配到,則對匹配結果按照相似度進行排序,並且對前兩個結果相似度進行比較,如果相似度一樣,則拋出異常,如果不一樣,則返回相似度最高的一個匹配結果。如果無法獲取到匹配結果,則對所有的匹配結果進行遍歷,判斷當前request具體是哪一部分參數無法匹配到結果。對於匹配結果的獲取,主要在addMatchingMappings()方法中
addMatchingMappings方法
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}