java源码 - SpringMVC(4)之 HandlerMapping
<spring.version>5.2.4.RELEASE</spring.version>
文章目录
1. 类关系依赖图与继承关系
主要看红线的,即如下继承关系:
2. AbstractHandlerMapping
还是见了很多次的模板模式,AbstractHandlerMapping设计了HandlerMapping实现的整体结构,子类只需要通过模板方法提供一些初始值或者具体的实现。
HandlerMapping的作用是根据request查找Handler和Interceptors。获取Handler的过程通过模板方法getHandlerInternal交给了子类。AbstractHandlerMapping中保存了所用配置的Interceptor,在获取到Handler后会自己根据从request提取的lookupPath将相应的Inte-rceptors装配上去,当然子类也可以通过getHandlerInternal方法设置自己的Interceptor,getHandlerInternal的返回值为Object类型。
2.1 初始化
AbstractHandlerMapping继承了WebApplicationObjectSupport,初始化时会自动调用模板方法initApplicationContext,AbstractHandlerMapping的创建就是在initApplicationContext方法里面实现的。
@Override
protected void initApplicationContext() throws BeansException { //钩子函数留给子类实现,将子类添加的拦截器加入到interceptors
extendInterceptors(this.interceptors);
//detectMappedInterceptors方法用于将Spring MVC容器及父容器中的所有MappedInter-ceptor类型的Bean添加到adaptedInterceptors属性
detectMappedInterceptors(this.adaptedInterceptors);
//initInterceptors方法的作用是初始化Interceptor,具体内容其实是将interceptors属性里所包含的对象按类型添加到adaptedInterceptors
initInterceptors();
}
/ * *
*子类可以覆盖的扩展钩子来注册额外的拦截器,
*给定配置的拦截器(参见{@link #setInterceptors})。
*
*将在{@link #initInterceptors()}调整指定的代码之前被调用
*拦截器到{@link HandlerInterceptor}实例。
*
默认实现为空。
* @param拦截器配置的拦截器列表(从不{@code null}),允许
*在现有的拦截器之前和之后添加更多的拦截器
* /
protected void extendInterceptors(List<Object> interceptors) {
}
/ * *
*检测类型为{@link MappedInterceptor}的bean,并将其添加到映射的拦截器列表中。
*
这是在任何{@link MappedInterceptor MappedInterceptors}之外被调用的,可能已经提供
*通过{@link #setInterceptors},默认情况下添加所有类型为{@link MappedInterceptor}的bean
*从当前上下文及其祖先。子类可以重写和改进这个策略。
添加{@link MappedInterceptor}实例到的空列表
* /
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}
/ * *
*初始化指定的拦截器,检查{@link MappedInterceptor}和
*适应{@link HandlerInterceptor}和{@link WebRequestInterceptor HandlerInterceptor}和
* {@link WebRequestInterceptor}如果需要的话。
* @see # setInterceptors
* @see # adaptInterceptor
* /
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
5.x 没有mappedInterceptors
mappedInterceptors:此类Interceptor在使用时需要与请求的url进行匹配,只有匹配成功后才会添加到getHandler的返回值HandlerExecutionChain里。它有两种获取途径:从interceptors获取或者注册到spring的容器中通过detectMappedInterceptors方法获取。
AbstractHandlerMapping中的Interceptor有三个List类型的属性:interceptors、adaptedInterceptors;
-
Interceptors:用于配置Spring MVC的拦截器,有两种设置方式:①注册Handler-Mapping时通过属性设置;②通过子类的extendInterceptors钩子方法进行设置。Interceptors并不会直接使用,而是通过initInterceptors方法按类型分配到adaptedInterceptors中进行使用,Interceptors只用于配置。
-
adaptedInterceptors:这种类型的Interceptor不需要进行匹配,在getHandler中会全部添加到返回值HandlerExecutionChain里面。它只能从interceptors中获取。
2.2 使用
HandlerMapping是通过getHandler方法来获取处理器Handler和拦截器Interceptor的。
/ * *
*查找给定请求的处理程序,返回到默认值
*处理程序,如果没有找到特定的。
* @param请求当前HTTP请求
返回对应的处理程序实例,或默认处理程序
* @see # getHandlerInternal
* /
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//又是一个模板方法,获取Handler
Object handler = getHandlerInternal(request);
if (handler == null) {
//如果没有就使用默认的Handler
//默认的Handler保存在AbstractHandler-Mapping的一个Object类型的属性defaultHandler中
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean名称还是解析处理程序?
if (handler instanceof String) {
String handlerName = (String) handler;
//如果找到的Handler是String类型,则以它为名到Spring MVC的容器里查找相应的Bean。
handler = obtainApplicationContext().getBean(handlerName);
}
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;
}
/**
*查找给定请求的处理程序,如果没有,返回{@code null}
*找到了特定的一个。该方法由{@link #getHandler}调用;
*一个{@code null}返回值将导致默认处理程序,如果设置了一个。
对于CORS飞行前请求,此方法应该返回一个不匹配的
*飞行前的请求,但基于URL的预期实际请求
*路径,从“访问-控制-请求-方法”头的HTTP方法,和
*来自“访问-控制-请求-报头”的报头因此允许
* CORS配置通过{@link #getCorsConfiguration(Object, HttpServletRequest)}获得,
注意:此方法也可能返回预先构建的{@link HandlerExecutionChain},
*将处理程序对象与动态确定的拦截程序相结合。
*静态指定的拦截器将合并到这样一个已有的链中。
* @param请求当前HTTP请求
* @返回相应的处理程序实例,如果没有找到,则返回{@code null}
* @抛出异常,如果有内部错误
*/
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
接下来看:
/**
*为给定的处理程序构建{@link HandlerExecutionChain},包括
*适用的拦截器。
默认实现构建一个标准的{@link HandlerExecutionChain}
*与给定的处理程序,处理程序映射的常见拦截器,和任何
匹配当前请求URL。拦截器
*按注册顺序添加。子类可以覆盖它
*为了扩展/重新排列拦截器列表。
注意:传递进来的处理程序对象可以是原始处理程序或a
*预构建的{@link HandlerExecutionChain}。这个方法应该处理这些
*显式地使用两种情况,要么构建一个新的{@link HandlerExecutionChain}
*或扩展现有的链。
如果只是在自定义子类中添加拦截器,请考虑调用
* {@code超级。getHandlerExecutionChain(处理器,请求)}和调用
在返回的链对象上* {@link HandlerExecutionChain#addInterceptor}。
解析的处理程序实例(never {@code null})
* @param请求当前HTTP请求
* @return HandlerExecutionChain (never {@code null})
* @see # getAdaptedInterceptors ()
*/
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) {
//找到匹配的interceptor
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
//等于找到对应该路径的拦截器
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
//否则就是全局拦截器,加入执行链
chain.addInterceptor(interceptor);
}
}
return chain;
}
再来看看MappedInterceptor 是个什么东西:
/*
*包含并委托对{@link HandlerInterceptor}的调用
*包括(可选排除)拦截器应该应用的路径模式。
*还提供了匹配逻辑来测试拦截器是否适用于给定的请求路径。
MappedInterceptor可以直接注册到any
* {@link org.springframework.web.servlet.handler.AbstractHandlerMethodMapping}。
*此外,类型为{@code MappedInterceptor}的bean被自动检测
* {@code AbstractHandlerMethodMapping}(包括祖先ApplicationContext的)
*有效地意味着拦截器注册为“全局”的所有处理程序映射。
*/
public final class MappedInterceptor implements HandlerInterceptor {
看注释可见,这是一个特定的拦截器。
3. AbstractUrlHandlerMapping
3.1 getHandlerInternal
从名字就可以看出它是通过url来进行匹配的。此系列大致原理是将url与对应的Handler保存在一个Map中,在getHandlerInternal方法中使用url从Map中获取Handler,AbstractUrlHandlerMapping中实现了具体用url从Map中获取Handler的过程,而Map的初始化则交给了具体的子孙类去完成。
AbstractUrlHandlerMapping重写了父类的getHandlerInternal():
/ * *
*查找给定请求的URL路径的处理程序。
* @param请求当前HTTP请求
* @返回处理程序实例,如果没有找到则{@code null}
* /
@Override
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
//我们需要直接关心默认处理程序,因为我们需要这样做
//还公开它的PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE。
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean名称还是解析的处理程序?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = obtainApplicationContext().getBean(handlerName);
}
//可以用来校验的Handler和request是否匹配,是模板方法
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
return handler;
}
lookupHandler方法用于使用lookupPath从Map中查找Handler,不过很多时候并不能直接从Map中get到,因为很多Handler都是用了Pattern的匹配模式,如“/show/article/”,这里的星号可以代表任意内容而不是真正匹配url中的星号,如果Pattern中包含PathVariable也不能直接从Map中获取到。另外,一个url还可能跟多个Pattern相匹配,这时还需要选择其中最优的,所以查找过程其实并不是直接简单地从Map里获取,单独写一个方法来做也是应该的。
/**
*查找给定URL路径的处理程序实例。
*
支持直接匹配,例如已注册的"/test"匹配"/test",
*和各种ant风格的模式匹配,例如注册的“/t*”匹配
*“/测试”和“/团队”。有关详细信息,请参见AntPathMatcher类。
*
寻找最精确的模式,其中最精确的定义为
*最长路径模式。
@param urlPath bean映射到的URL
* @param请求当前HTTP请求(暴露映射到的路径)
* @返回相关的处理程序实例,如果没有找到,则返回{@code null}
* @see # exposePathWithinMapping
* @see org.springframework.util.AntPathMatcher
*/
@Nullable
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// 直接匹配
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// Bean名称还是解析处理程序?
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.isTraceEnabled() && matchingPatterns.size() > 1) {
logger.trace("Matching patterns " + 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名称还是解析处理程序?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);
//可能有多个“最佳模式”,让我们确保我们有正确的URI模板变量匹配他们
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.isTraceEnabled() && uriTemplateVariables.size() > 0) {
logger.trace("URI variables " + uriTemplateVariables);
}
return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
}
// No handler found...
return null;
}
再来看返回方法buildPathExposingHandler:
/ * *
*为给定的原始处理程序构建一个处理程序对象,公开实际的
*处理程序,{@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}以及
*执行处理程序之前的{@link #URI_TEMPLATE_VARIABLES_ATTRIBUTE}。
*
默认实现构建一个{@link HandlerExecutionChain}
*使用一个特殊的拦截器来公开路径属性和uri模板变量
* @param rawHandler要公开的raw处理程序
* @param pathWithinMapping path to expose before执行处理程序
* @param uriTemplateVariables URI模板变量,如果没有找到变量,可以是{@code null}
* @return最终的处理程序对象
* /
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, @Nullable Map<String, String> uriTemplateVariables) {
HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
}
return chain;
}
在buildPathExposingHandler方法中给Handler注册两个内部拦截器PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor,这两个拦截器分别在preHandle中调用了exposePathWithinMapping和exposeUriTemplateVariables方法将相应内容设置到了request的属性。
3.2 初始化
从spring容器或者子类加载handler。
/**
*调用{@link #detectHandlers()}方法
*超类的初始化。
*/
@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
detectHandlers();
}
/**
*注册在当前ApplicationContext中找到的所有处理程序。
处理程序的实际URL确定取决于具体情况
* {@link #determineUrlsForHandler(String)}实现。一个豆
*没有这样的url可以被确定,就是不被认为是一个处理程序。
* @throws org.springframework.beans。如果处理程序不能注册,则BeansException异常
* @see # determineUrlsForHandler(字符串)
*/
protected void detectHandlers() throws BeansException {
/**
*为给定的URL路径注册指定的处理程序。
* @param urlPaths该bean应该映射到的url
处理程序bean的名称
* @抛出BeansException,如果处理程序不能被注册
* @抛出IllegalStateException,如果注册的处理程序有冲突
*/
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
Assert.notNull(urlPaths, "URL path array must not be null");
for (String urlPath : urlPaths) {
registerHandler(urlPath, beanName);
}
}
注意:registerHandler方法并不是自己调用,也不是父类调用,而是子类调用。
/**
*为给定的URL路径注册指定的处理程序。
@param urlPath bean应该映射到的URL
处理程序实例或处理程序bean名称字符串
* (bean名称将自动解析为相应的处理程序bean)
* @抛出BeansException,如果处理程序不能被注册
* @抛出IllegalStateException,如果注册的处理程序有冲突
*/
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.isTraceEnabled()) {
logger.trace("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
else if (urlPath.equals("/*")) {
if (logger.isTraceEnabled()) {
logger.trace("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
else {
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isTraceEnabled()) {
logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}
AbstractUrlHandlerMapping里面定义了整体架构,子类只需要将Map初始化就可以了。
4. SimpleUrlHandlerMapping
SimpleUrlHandlerMapping定义了一个Map变量(自己定义一个Map主要有两个作用,第一是方便配置,第二是可以在注册前做一些预处理,如确保所有url都以“/”开头),将所有的url和Handler的对应关系放在里面,最后注册到父类的Map中;而AbstractDetectingUrlHandlerMapping则是将容器中的所有bean都拿出来,按一定规则注册到父类的Map中。
/**
*调用{@link #registerHandlers}方法
*超类的初始化。
*/
@Override
public void initApplicationContext() throws BeansException {
super.initApplicationContext();
registerHandlers(this.urlMap);
}
registerHandlers内部又调用了Abstract-UrlHandlerMapping的registerHandler方法将我们配置的urlMap注册到AbstractUrlHandler-Mapping的Map中。
/**
*注册URL映射中指定的对应路径的所有处理程序。
@param urlMap以URL路径作为键,处理程序bean或bean名称作为值的映射
* @抛出BeansException,如果处理程序无法注册
* @抛出IllegalStateException,如果注册的处理程序有冲突
*/
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.trace("No patterns in " + formatMappingName());
}
else {
urlMap.forEach((url, handler) -> {
//如果还没有出现,则在前加上斜杠。
if (!url.startsWith("/")) {
url = "/" + url;
}
//从处理程序bean名称中删除空格。
if (handler instanceof String) {
handler = ((String) handler).trim();
}
//调用父类的负责方法
registerHandler(url, handler);
});
if (logger.isDebugEnabled()) {
List<String> patterns = new ArrayList<>();
if (getRootHandler() != null) {
patterns.add("/");
}
if (getDefaultHandler() != null) {
patterns.add("/**");
}
patterns.addAll(getHandlerMap().keySet());
logger.debug("Patterns " + patterns + " in " + formatMappingName());
}
}
}
org.springframework.web.servlet.handler.AbstractUrlHandlerMapping:
5. AbstractDetectingUrlHandlerMapping
AbstractDetectingUrlHandlerMapping也是通过重写initApplicationContext来注册Handler的,里面调用了detectHandlers方法,在detectHandlers中根据配置的detectHand-lersInAn-cestorContexts参数从Spring MVC容器或者Spring MVC及其父容器中找到所有bean的beanName,然后用determineUrlsForHandler方法对每个beanName解析出对应的urls,如果解析结果不为空则将解析出的urls和beanName(作为Handler)注册到父类的Map,注册方法依然是调用AbstractUrlHandlerMapping的registerHandler方法。
使用beanName解析urls的determineUrlsForHandler方法是模板方法,交给具体子类实现。
/**
*调用{@link #detectHandlers()}方法
*超类的初始化。
*/
@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
detectHandlers();
}
/**
*注册在当前ApplicationContext中找到的所有处理程序。
处理程序的实际URL确定取决于具体情况
* {@link #determineUrlsForHandler(String)}实现。一个豆
*没有这样的url可以被确定,就是不被认为是一个处理程序。
* @throws org.springframework.beans。如果处理程序不能注册,则BeansException异常
* @see # determineUrlsForHandler(字符串)
*/
protected void detectHandlers() throws BeansException {
ApplicationContext applicationContext = obtainApplicationContext();
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) {
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// 找到的URL路径:让我们把它看作一个处理程序。
//调用父类的registerHandler
registerHandler(urls, beanName);
}
}
if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {
logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());
}
}
/ * *
*确定给定处理程序bean的url。
* @param beanName候选bean的名称
@返回为bean确定的url,如果没有,则返回空数组
* /
protected abstract String[] determineUrlsForHandler(String beanName);
目前它的子类只有:
BeanNameUrlHandlerMapping是检查beanName和alias是不是以“/”开头,如果是则将其作为url,里面只有一个determineUrlsForHandler方法:
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
/ * *
*检查给定bean的url名称和别名,以“/”开头。
* /
@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);
}
}
至此,关于HandlerMapping其实只要搞清楚,handler从哪里来,handler怎么调用,就差不多可以弄明白了。其他的基本上就是为了满足框架的可扩展性而设计使用的设计模式。
6. AbstractHandlerMethodMapping
AbstractHandlerMethodMapping直接继承自AbstractHandlerMapping。
AbstractHandlerMethodMapping系列是将Method作为Handler来使用的,这也是我们现在用得最多的一种Handler。
比如经常使用的@RequestMapping所注释的方法就是这种Handler,它专门有一个类型——HandlerMethod,也就是Method类型的Handler。
6.1 初始化
先找到MappingRegistry这个内部类:
/ * *
*维护所有映射到处理程序方法,暴露方法的注册表
*执行查找和提供并发访问。
*
Package-private用于测试目的。
* /
class MappingRegistry {
本文地址:https://blog.csdn.net/littlewhitevg/article/details/107347814
推荐阅读
-
Java中的容器(集合)之ArrayList源码解析
-
死磕 java同步系列之CyclicBarrier源码解析——有图有真相
-
JAVA WEB快速入门之从编写一个基于SpringBoot+Mybatis快速创建的REST API项目了解SpringBoot、SpringMVC REST API、Mybatis等相关知识
-
Java中的容器(集合)之HashMap源码解析
-
大厂面试手撕源码之java数组拷贝
-
JAVA WEB快速入门之从编写一个基于SpringMVC框架的网站了解Maven、SpringMVC、SpringJDBC
-
java 工作流项目源码 SSM 框架 Activiti-master springmvc 有手机端功能
-
java 快速开发框架平台 二次开发 代码生成器 springmvc SSM后台框架源码
-
Java之LinkedList源码分析(第三篇:添加元素-List接口)
-
java源码 - SpringMVC(4)之 HandlerMapping