HandlerMapping繼承關係圖:
1.BeanNameUrlHandlerMapping
配置文件中配置controller的bean,且bean的id必須以“/”開頭,id就是controller可以處理的url
<bean id = "/hello" class="com.liyao.controller.HelloController"/>
2.SimpleUrlHandlerMapping
需要在配置文件中配置controller的bean以及mapping:
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hi">hi</prop>
</props>
</property>
</bean>
<bean id = "hi" class="com.lic.controller.HiController"/>
3.RequestMappingUrlHandlerMapping
基於@RequestMapping註解對應映射
AbstractUrlHandlerMapping 映射器映射出來的是 handler 是 Controller 對象, 也就是類級別的處理器
AbstractHandlerMethodMapping 映射器映射出來的 handler 是 HandlerMethod 對象, 也就是方法級別的處理器
DispatcherServlet#getHandler()方法實現:
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
//遍歷所有HandlerMapping, 獲取適合當前請求的映射處理器
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
/**
* 1.遍歷所有的HandlerMapping,根據Request獲取到合適的HandlerMapping
* 2.利用HandlerMapping通過請求信息獲取Handler處理器幷包裝爲HandlerExecutionChain執行鏈
*
* {@link AbstractHandlerMapping#getHandler(HttpServletRequest)}
* hm ==> RequestMappingInfoHandlerMapping
*/
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
分析:
- 遍歷所有的註冊HandlerMapping,根據Request獲取到合適的HandlerMapping
- 利用HandlerMapping通過請求信息獲取Handler處理器幷包裝爲HandlerExecutionChain執行鏈返回
AbstractHandlerMapping#getHandler()方法實現:
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
/**
* 由子類實現, 根據請求信息獲取指定的Handler
* {@link AbstractHandlerMethodMapping#getHandlerInternal(HttpServletRequest)}
* {@link AbstractUrlHandlerMapping#getHandlerInternal(javax.servlet.http.HttpServletRequest)}
*/
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
handler = obtainApplicationContext().getBean(handlerName);
}
/**
* 將handler和request包裝爲HandlerExecutionChain,在HandlerExecutionChain設置了相關過濾器
*/
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
分析:
- 在AbstractHandlerMapping子類中根據請求信息獲取指定的Handler
- 如果獲取的handler是一個String類型的名稱, 則從容器中獲取handler實例
- 將handler和request包裝爲HandlerExecutionChain,在HandlerExecutionChain設置了相關過濾器
1. AbstractHandlerMapping子類一: AbstractHandlerMethodMapping
AbstractHandlerMethodMapping#getHandlerInternal()方法實現:
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//lookupPath爲請求路徑信息
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock(); //獲取讀鎖
try {
/**
* 1. 獲取HandlerMethod實例(不健全, 數據沒有封裝完成)
*/
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
/**
* 2. 重塑HandlerMethod實例 ==> 重點
*/
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
分析:
- 根據請求信息獲取HandlerMethod實例
- 封裝HandlerMethod實例
(1). AbstractHandlerMethodMapping#lookupHandlerMethod()方法實現:
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
/**
* 由映射處理器映射出對應的MappingInfo信息, 可能獲取多個
*/
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
/**
* 將HandlerMethod實例與Request進行包裝, 添加到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()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
//對所有符合條件的處理器進行排序
matches.sort(comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
}
/**
* 獲取matches集合中最合適的處理器
*/
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
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();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
/**
* {@link RequestMappingInfoHandlerMapping#handleMatch(org.springframework.web.servlet.mvc.method.RequestMappingInfo, String, HttpServletRequest)}
*/
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
分析:
- 根據url從註冊中心獲取對應的MappingInfo信息,封裝到directPathMatches集合中
- 將HandlerMethod實例與Request進行包裝, 並且創建Match實例, 在該實例中封裝了HandlerMethod方法
- 由映射處理器(RequestMappingInfoHandlerMapping) 映射出對應的handler
AbstractHandlerMethodMapping#addMatchingMappings()方法實現:
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
/**
* 根據請求路徑從mappingLookup集合中獲取處理方法, 將Method封裝到Match實例中
* 後面處理請求時會利用反射執行該方法
*/
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
(2) HandlerMethod#createWithResolvedBean()方法實現:
public HandlerMethod createWithResolvedBean() {
Object handler = this.bean;
if (this.bean instanceof String) { //如果bean不是實例而是一個BeanName,則從工廠中獲取該bean實例
Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
String beanName = (String) this.bean;
// 從工廠中獲取bean
handler = this.beanFactory.getBean(beanName);
}
/**
* 問題: 這裏爲什麼要重新創建一個HandlerMethod實例,而不是在原有的HandlerMethod實例上進行修改?
*/
return new HandlerMethod(this, handler);
}
private HandlerMethod(HandlerMethod handlerMethod, Object handler) {
Assert.notNull(handlerMethod, "HandlerMethod is required");
Assert.notNull(handler, "Handler object is required");
this.bean = handler; //反射執行Method時需要傳入實例對象
this.beanFactory = handlerMethod.beanFactory;
this.beanType = handlerMethod.beanType;
this.method = handlerMethod.method;
this.bridgedMethod = handlerMethod.bridgedMethod;
this.parameters = handlerMethod.parameters;
this.responseStatus = handlerMethod.responseStatus;
this.responseStatusReason = handlerMethod.responseStatusReason;
this.resolvedFromHandlerMethod = handlerMethod;
}
這裏有一個疑問: 爲什麼要重新創建一個HandlerMethod實例,而不是在原有的HandlerMethod實例上進行修改?
1.1 AbstractHandlerMethodMapping子類: RequestMappingInfoHandlerMapping
在容器初始化過程中創建映射器(RequestMappingHandlerMapping)對象時,會尋找所有被@Controller 註解類中被 @RequestMapping 註解的方法,然後解析方法上的 @RequestMapping 註解,把解析結果封裝成 RequestMappingInfo 對象,也就是說RequestMappingInfo 對象是用來裝載方法的匹配相關信息,每個匹配的方法都會對應一個 RequestMappingInfo 對象
RequestMappingInfoHandlerMapping#handleMatch()方法實現:
@Override
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
super.handleMatch(info, lookupPath, request);
String bestPattern;
Map<String, String> uriVariables;
Set<String> patterns = info.getPatternsCondition().getPatterns();
if (patterns.isEmpty()) {
bestPattern = lookupPath;
uriVariables = Collections.emptyMap();
}
else {
bestPattern = patterns.iterator().next();
uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
}
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
if (isMatrixVariableContentAvailable()) {
Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables);
request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);
}
Map<String, String> decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);
if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
}
}
MappingRegistry#getMappingsByUrl()方法實現:
@Nullable
public List<T> getMappingsByUrl(String urlPath) {
return this.urlLookup.get(urlPath);
}
由此可知, 在初始化SpringMVC時處理器已經註冊到urlLookup集合中, key爲url, 在MappingRegistry#register()方法中實現了對處理器的註冊
AbstractHandlerMethodMapping.MappingRegistry#register()方法實現
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
/**
* mappingLookup: 維護請求信息(RequestMappingInfo)與HandlerMethod的映射關係
*/
this.mappingLookup.put(mapping, handlerMethod);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
/**
* urlLookup: 維護url與請求信息(RequestMappingInfo)的映射關係
* 後面會根據Url找RequestMappingInfo, 再根據RequestMappingInfo找HandlerMethod對請求進行處理
*/
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
在this.urlLookup.add(url, mapping) 處添加斷點查看調用棧:
分析:
- 模塊1主要邏輯爲創建以及配置Web應用上下文(WebApplicationContext)
- 模塊2主要邏輯爲springMVC相關bean對象註冊解析, 即WebApplicationContext的實例化
- 模塊3主要邏輯爲遍歷所有Controller類, 對類中定義的所有處理方法進行註冊,即註冊Handler處理器
模塊3邏輯分析:
RequestMappingInfoHandlerMapping類實現了InitializingBean接口並重寫了afterPropertiesSet(), 在調用初始化方法時, 會觸發afterPropertiesSet()方法, 將啓動對處理器(handler)的探測以及註冊
AbstractHandlerMethodMapping#afterPropertiesSet()方法實現:
@Override
public void afterPropertiesSet() {
//初始化Handler方法, 就是對編寫的Control層方法進行註冊, key爲方法的訪問路徑, value爲對方法的包裝類HandlerMethod
initHandlerMethods();
}
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
//獲取對應bean的Class
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
/**
* isHandler()方法用來判斷是否符合註冊條件, 具體的判斷邏輯由子類實現
*/
if (beanType != null && isHandler(beanType)) {
//對Controller類中所有的方法進行探測
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
AbstractHandlerMethodMapping#detectHandlerMethods()方法實現:
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
methods.forEach((method, mapping) -> {
/**
* 循環遍歷所有的方法,進行註冊
* handler爲controller類實例, 每一個HandlerMethod中都維護着該實例, 因爲在後面執行該方法時需要傳入該實例
*/
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
2.AbstractHandlerMapping子類二: AbstractUrlHandlerMapping
AbstractUrlHandlerMapping#getHandlerInternal()方法實現:
@Override
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
//獲取請求路徑
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
/**
* 根據請求路徑獲取handler
*/
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Mapping [" + lookupPath + "] to " + handler);
}
else if (handler == null && logger.isTraceEnabled()) {
logger.trace("No handler mapping found for [" + lookupPath + "]");
}
return handler;
}
AbstractUrlHandlerMapping#lookupHandler()方法實現:
@Nullable
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
//嘗試直接匹配
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
//嘗試模式匹配
List<String> matchingPatterns = new ArrayList<>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern + "/");
}
}
}
String bestMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
matchingPatterns.sort(patternComparator);
if (logger.isDebugEnabled()) {
logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
}
bestMatch = matchingPatterns.get(0);
}
if (bestMatch != null) {
handler = this.handlerMap.get(bestMatch);
if (handler == null) {
if (bestMatch.endsWith("/")) {
handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
}
if (handler == null) {
throw new IllegalStateException(
"Could not find handler for best pattern match [" + bestMatch + "]");
}
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);
// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
// for all of them
Map<String, String> uriTemplateVariables = new LinkedHashMap<>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
if (logger.isDebugEnabled()) {
logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
}
return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
}
// No handler found...
return null;
}
在上面方法中都是通過handlerMap獲取指定handler, 那麼接下來就看下怎麼將handler對象加入handlerMap集合中
AbstractUrlHandlerMapping#registerHandler()方法實現:
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Assert.notNull(urlPath, "URL path must not be null");
Assert.notNull(handler, "Handler object must not be null");
Object resolvedHandler = handler;
// Eagerly resolve handler if referencing singleton via name.
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
ApplicationContext applicationContext = obtainApplicationContext();
if (applicationContext.isSingleton(handlerName)) {
resolvedHandler = applicationContext.getBean(handlerName);
}
}
Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
throw new IllegalStateException(
"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
}
else {
if (urlPath.equals("/")) {
if (logger.isInfoEnabled()) {
logger.info("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
if (logger.isInfoEnabled()) {
logger.info("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
else {
/**
* 此處完成了對Handler的註冊
*/
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isInfoEnabled()) {
logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}
在AbstractUrlHandlerMapping#registerHandler()方法中完成了對handler的註冊
查看該方法的調用棧:
通過調用棧可知, 是在子類中調用父類AbstractUrlHandlerMapping的registerHandler()方法
2.1 AbstractUrlHandlerMapping子類一: SimpleUrlHandlerMapping
SimpleUrlHandlerMapping#registerHandlers()方法實現:
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
}
else {
urlMap.forEach((url, handler) -> {
// Prepend with slash if not already present.
if (!url.startsWith("/")) {
url = "/" + url;
}
// Remove whitespace from handler bean name.
if (handler instanceof String) {
handler = ((String) handler).trim();
}
registerHandler(url, handler);
});
}
}
在SimpleUrlHandlerMapping#registerHandlers(Map<String, Object> urlMap)中調用了SimpleUrlHandlerMapping#registerHandlers(
String urlPath, Object handler)方法
SimpleUrlHandlerMapping#initApplicationContext()方法實現:
@Override
public void initApplicationContext() throws BeansException {
/**
* 其頂級父類AbstractHandlerMapping繼承了WebApplicationObjectSupport,容器初始化時會自動調用模板方法
* initApplicationContext, 這裏子類重寫該方法並加了一些邏輯, 主要是爲了將匹配該映射器的Handler對象加入
* 到handlerMap集合中
*/
super.initApplicationContext();
registerHandlers(this.urlMap);
}
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
}
else {
urlMap.forEach((url, handler) -> {
// Prepend with slash if not already present.
if (!url.startsWith("/")) {
url = "/" + url;
}
// Remove whitespace from handler bean name.
if (handler instanceof String) {
handler = ((String) handler).trim();
}
registerHandler(url, handler);
});
}
}
2.2 AbstractUrlHandlerMapping子類二: BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping中沒有registerHandlers()方法, 而是由其父類AbstractUrlHandlerMapping進行實現
AbstractDetectingUrlHandlerMapping#initApplicationContext()方法實現:
@Override
public void initApplicationContext() throws ApplicationContextException {
/**
* 其頂級父類AbstractHandlerMapping繼承了WebApplicationObjectSupport,容器初始化時會自動調用模板方法
* initApplicationContext, 這裏子類重寫該方法並加了一些邏輯, 主要是爲了將匹配該映射器的Handler對象加入
* 到handlerMap集合中
*/
super.initApplicationContext();
detectHandlers();
}
protected void detectHandlers() throws BeansException {
ApplicationContext applicationContext = obtainApplicationContext();
if (logger.isDebugEnabled()) {
logger.debug("Looking for URL mappings in application context: " + applicationContext);
}
/**
* 將SpringMVC容器中註冊的Bean的name都找出來放進數組中
*/
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));
// Take any bean name that we can determine URLs for.
for (String beanName : beanNames) {
/**
* 匹配到符合該映射器的bean的name
*/
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
/**
* 調用父類(AbstractUrlHandlerMapping)的registerHandler方法將匹配的beanName和urls分別作爲key和value
* 裝進handlerMap集合中
*/
registerHandler(urls, beanName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
}
}
}
}
BeanNameUrlHandlerMapping#determineUrlsForHandler方法實現:
@Override
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<>();
if (beanName.startsWith("/")) {
urls.add(beanName);
}
String[] aliases = obtainApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
至此, 處理器的獲取解析完成;
相關文章:
SpringMVC源碼解析一(在Spring源碼項目中搭建SpringMVC源碼模塊)
SpringMVC源碼解析三(處理映射器HandlerMapping的解析)
SpringMVC源碼解析四(處理適配器HandlerAdapter的解析)
SpringMVC源碼解析五(HandlerMethod執行過程解析)