實現HandlerMapping接口的類用來定義request請求和handler object之間的映射關係;request請求可以理解爲路由url、RequestMappingInfo,handler object理解爲控制器類;RequestMappingHandlerMapping類就是實現此接口並將容器中所有的控制器的RequestMappingInfo請求和HandlerMethod註冊到內存之中,方便真實的請求發送過來調用具體的控制器方法;本文將以RequestMappingHandlerMapping爲主線來講解。
接口源碼如下:
public interface HandlerMapping {
/**
* 返回一個包含handler Object和所有攔截器的HandlerExecutionChain
*/
@Nullable
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
1.HandlerMapping的初始化
容器加載時DispatcherServlet中的初始化方法initStrategies會被調用,裏面的initHandlerMappings(context)方法會被執行,源碼如下:
//容器中HandlerMapping接口實現類集合
@Nullable
private List<HandlerMapping> handlerMappings;
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//判定是否檢測所有的HandlerMapping
if (this.detectAllHandlerMappings) {
//查看容器中所有的實現了HandlerMapping的bean
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// 使用實現類的order進行優先級排序,升序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
//加載缺省的HandlerMapping
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
上面的源碼是從容器中獲取HandlerMapping接口的實現類,其中包括RequestMappingHandlerMapping類實例,那這個類實例實在哪裏加載的呢?請查看另一篇文章RequestMappingHandlerMapping源碼分析;
2.RequestMappingHandlerMapping處理reques請求
前端發送過來一個request請求首先進入DispatcherServlet的doService方法,再進入doDispatch方法,那我們看下doDispatch方法的源碼:
-
本文的重點是通過request請求如何獲取HandlerExecutionChain處理程序執行器鏈;HandlerExecutionChain是一個很重要的類,所有的HandlerMethod最終都要包裝成HandlerExecutionChain後纔可以使用;
跳出正文主題分析下HandlerExecutionChain類:
Handler execution chain, consisting of handler object and any handler interceptors.
Returned by HandlerMapping’s {@link HandlerMapping#getHandler} method.
上面官方說明已經說的很清楚了,該類包含handler object(HandlerMethod)和所有的handler interceptors;而且該類的生成只能通過HandlerMapping接口的getHandler方法,具體由AbstractHandlerMapping抽象類實現;AbstractHandlerMapping類實現源碼:
/**
* 根據request請求獲取HandlerExecutionChain處理程序執行器鏈
* Look up a handler for the given request, falling back to the default
* handler if no specific one is found.
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//獲取Handler object即HandlerMethod對象
Object handler = getHandlerInternal(request);
if (handler == null) {
//如果沒有找到匹配的HandlerMethod對象,那麼就獲取默認的handler
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
//根據上面獲取的handler object獲取處理程序執行器鏈類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 (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
看下getHandlerInternal方法如何獲取HandlerMethod對象:
/**
* 通過request請求獲取對應的HandlerMethod類
*/
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//獲取請求URL
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
//獲取URL對應的HandlerMethod,重點是我們如何獲取HandlerMethod對象?
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
看lookupHandlerMethod源碼:
/**
* 通過URL獲取HandlerMethod對象
*/
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
//通過URL獲取RequestMappingInfo集合
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//將RequestMappingInfo對象和HandlerMethod對象封裝到Match對象中存到matches集合
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()) {
//獲取集合中第一個Match對象
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
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);
handleMatch(bestMatch.mapping, lookupPath, request);
//返回HandlerMethod對象
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
上面的代碼有一個this.mappingRegistry.getMappingsByUrl(lookupPath)方法獲取url對應的RequestMappingInfo對象,源碼如下:
//URL和RequestMappingInfo集合
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
/**
* 返回與URL匹配的RequestMappingInfo集合
*/
@Nullable
public List<T> getMappingsByUrl(String urlPath) {
return this.urlLookup.get(urlPath);
}
上面的源碼顯示RequestMappingInfo對象是從urlLookup集合中獲取的,那urlLookup集合中的數據又是從哪裏來的呢?請看我的另外一篇文章RequestMappingHandlerMapping源碼分析。
上面代碼有一個addMatchingMappings方法,是通過這個方法獲取到的HandlerMethod對象,看下源碼:
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
//循環遍歷RequestMappingInfo對象
for (T mapping : mappings) {
//
T match = getMatchingMapping(mapping, request);
if (match != null) {
//通過this.mappingRegistry.getMappings()獲取HandlerMethod對象
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
//RequestMappingInfo和HandlerMethod集合
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
/**
* Return all mappings and handler methods. Not thread-safe.
* @see #acquireReadLock()
*/
public Map<T, HandlerMethod> getMappings() {
return this.mappingLookup;
}
上面源碼獲取HandlerMethod對象實際上是從mappingLookUp集合之中獲取的,那你可能會問mappingLookup集合中的數據又是從哪裏獲取到的呢?請看我的另外一篇文章RequestMappingHandlerMapping源碼分析;
回到正文,我們看下mappedHandler = getHandler(processedRequest);方法,源碼如下:
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code null} if no handler could be found
*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
//循環HandlerMapping實現類集合,其中包括RequestMappingHandlerMapping
for (HandlerMapping mapping : this.handlerMappings) {
//調用HandlerMapping實現類的getHandler方法,並獲取程序執行器鏈類對象
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
//如果匹配直接返回,否則返回null
return handler;
}
}
}
return null;
}
通過上面我們一步步的分析源碼,知道了HandlerExecutionChain處理程序執行器鏈是如何獲取的,HandlerExecutionChain裏面包含了請求對應的HandlerMethod對象和所有有關的連接器;接下來的一篇文章對HandlerAdapter接口進行分析,理解拿到HandlerExecutionChain後如何通過適配器類調用控制器方法;
GitHub地址:https://github.com/mingyang66/spring-parent/tree/master/doc/base