类图

HandlerMapping 的子类比较多,整体类图如下:

  • 绿框 AbstractHandlerMapping 抽象类,实现了【获得请求对应的处理器和拦截器们】的骨架逻辑,而暴露 #getHandlerInternal(HttpServletRequest request) 抽象方法,交由子类实现。这就是我们常说的“模板方法模式” 。

  • AbstractHandlerMapping 的子类,分成两派,分别是:

    • 红框 AbstractUrlHandlerMapping 系,基于 URL 进行匹配。实际我们开发时,这种方式已经基本不用了,被 @RequestMapping 等注解的方式所取代。不过,Spring MVC 内置的一些路径匹配,还是使用这种方式。
    • 黄框 AbstractHandlerMethodMapping 系,基于 Method 进行匹配。@RequestMapping 等注解的方式
  • 白框 MatchableHandlerMapping 接口,定义判断请求和指定 pattern 路径是否匹配的接口方法。

AbstractHandlerMapping

该类实现 HandlerMapping、Ordered、BeanNameAware接口,继承WebApplicationObjectSupport 抽象类,HandlerMapping抽象基类,实现了【获得请求对应的处理器和拦截器们】的骨架逻辑,而暴露 #getHandlerInternal(HttpServletRequest request) 抽象方法,交由子类实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// AbstractHandlerMapping.java

/**
* 默认处理器
*/
@Nullable
private Object defaultHandler;

/**
* URL 路径工具类
*/
private UrlPathHelper urlPathHelper = new UrlPathHelper();

/**
* 路径匹配器
*/
private PathMatcher pathMatcher = new AntPathMatcher();

/**
* 配置的拦截器数组.
*
* 在 {@link #initInterceptors()} 方法中,初始化到 {@link #adaptedInterceptors} 中
*
* 添加方式有两种:
*
* 1. {@link #setInterceptors(Object...)} 方法
* 2. {@link #extendInterceptors(List)} 方法
*/
private final List<Object> interceptors = new ArrayList<>();

/**
* 初始化后的拦截器 HandlerInterceptor 数组
*/
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();

/**
* TODO cors
*/
private CorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();

/**
* TODO cors
*/
private CorsProcessor corsProcessor = new DefaultCorsProcessor();

/**
* 顺序
*/
private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered

/**
* Bean 名字
*/
@Nullable
private String beanName;
  • defaultHandler 属性,默认处理器。在获得不到处理器时,可使用该属性
  • interceptors 属性,配置的拦截器数组
1
2
3
4
5
// AbstractHandlerMapping.java

public void setInterceptors(Object... interceptors) {
this.interceptors.addAll(Arrays.asList(interceptors));
}
  • adaptedInterceptors 属性,初始化后的拦截器 HandlerInterceptor 数组。

initApplicationContext

初始化拦截器

1
2
3
4
5
6
7
8
9
10
11
// AbstractHandlerMapping.java

@Override
protected void initApplicationContext() throws BeansException {
// <1> 空方法。交给子类实现,用于注册自定义的拦截器到 interceptors 中。目前暂无子类实现。
extendInterceptors(this.interceptors);
// <2> 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中
detectMappedInterceptors(this.adaptedInterceptors);
// <3> 将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中
initInterceptors();
}
  • 1.调用 #extendInterceptors(List
  • 2.扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中。
1
2
3
4
5
6
7
8
9
// AbstractHandlerMapping.java

protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
// 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中
// MappedInterceptor 会根据请求路径做匹配,是否进行拦截。
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
obtainApplicationContext(), MappedInterceptor.class, true, false).values());
}
  • 3.调用 #initInterceptors() 方法,将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// AbstractHandlerMapping.java

protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
// 遍历 interceptors 数组
for (int i = 0; i < this.interceptors.size(); i++) {
// 获得 interceptor 对象
Object interceptor = this.interceptors.get(i);
if (interceptor == null) { // 若为空,抛出 IllegalArgumentException 异常
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
// 将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中
// 注意,HandlerInterceptor 无需进行路径匹配,直接拦截全部
this.adaptedInterceptors.add(adaptInterceptor(interceptor)); // <x>
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// AbstractHandlerMapping.java

protected HandlerInterceptor adaptInterceptor(Object interceptor) {
// HandlerInterceptor 类型,直接返回
if (interceptor instanceof HandlerInterceptor) {
return (HandlerInterceptor) interceptor;
// WebRequestInterceptor 类型,适配成 WebRequestHandlerInterceptorAdapter 对象,然后返回
} else if (interceptor instanceof WebRequestInterceptor) {
return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
// 错误类型,抛出 IllegalArgumentException 异常
} else {
throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
}
}

getHandler

获得请求对应的 HandlerExecutionChain 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// AbstractHandlerMapping.java

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// <1> 获得处理器。该方法是抽象方法,由子类实现
Object handler = getHandlerInternal(request);
// <2> 获得不到,则使用默认处理器
if (handler == null) {
handler = getDefaultHandler();
}
// <3> 还是获得不到,则返回 null
if (handler == null) {
return null;
}
// Bean name or resolved handler?
// <4> 如果找到的处理器是 String 类型,则从容器中找到 String 对应的 Bean 类型作为处理器。
// TODO 芋艿,什么情况???
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}

// <5> 获得 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());
}

// <6> TODO 芋艿 cors
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);
}

// <7> 返回
return executionChain;
}
  • 4处,如果找到的处理器是 String 类型,则调用 BeanFactory#getBean(String name) 方法,从容器中找到 String 对应的 Bean 类型作为处理器。
  • 调用 #getHandlerExecutionChain(Object handler, HttpServletRequest request) 方法,获得 HandlerExecutionChain 对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// AbstractHandlerMapping.java

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 创建 HandlerExecutionChain 对象
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

// 获得请求路径
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
// 遍历 adaptedInterceptors 数组,获得请求匹配的拦截器
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 需要匹配,若路径匹配,则添加到 chain 中
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { // 匹配
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
// 无需匹配,直接添加到 chain 中
} else {
chain.addInterceptor(interceptor);
}
}
return chain;
}

重心在于从 adaptedInterceptors 中,获得请求路径对应的符合的 HandlerInterceptor 数组。

MatchableHandlerMapping

定义判断请求和指定 pattern 路径是否匹配的接口方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// MatchableHandlerMapping.java

public interface MatchableHandlerMapping extends HandlerMapping {

/**
* 判断请求和指定 `pattern` 路径是否匹配的接口方法
*
* Determine whether the given request matches the request criteria.
* @param request the current request
* @param pattern the pattern to match
* @return the result from request matching, or {@code null} if none
*/
@Nullable
RequestMatchResult match(HttpServletRequest request, String pattern);

}

请求匹配结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// RequestMatchResult.java

public class RequestMatchResult {

/**
* 匹配上的路径
*/
private final String matchingPattern;

/**
* 被匹配的路径
*/
private final String lookupPath;

/**
* 路径匹配器
*/
private final PathMatcher pathMatcher;

/**
* Create an instance with a matching pattern.
* @param matchingPattern the matching pattern, possibly not the same as the
* input pattern, e.g. inputPattern="/foo" and matchingPattern="/foo/".
* @param lookupPath the lookup path extracted from the request
* @param pathMatcher the PathMatcher used
*/
public RequestMatchResult(String matchingPattern, String lookupPath, PathMatcher pathMatcher) {
Assert.hasText(matchingPattern, "'matchingPattern' is required");
Assert.hasText(lookupPath, "'lookupPath' is required");
Assert.notNull(pathMatcher, "'pathMatcher' is required");
this.matchingPattern = matchingPattern;
this.lookupPath = lookupPath;
this.pathMatcher = pathMatcher;
}


/**
* Extract URI template variables from the matching pattern as defined in
* {@link PathMatcher#extractUriTemplateVariables}.
* @return a map with URI template variables
*/
public Map<String, String> extractUriTemplateVariables() {
return this.pathMatcher.extractUriTemplateVariables(this.matchingPattern, this.lookupPath);
}

}

目前实现 MatchableHandlerMapping 接口的类,有 RequestMappingHandlerMapping 类和 AbstractUrlHandlerMapping 抽象类。

DispatcherServlet

在 DispatcherServlet 中,通过调用 #initHandlerMappings(ApplicationContext context) 方法,初始化 HandlerMapping 们。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// DispatcherServlet.java

/**
* Well-known name for the HandlerMapping object in the bean factory for this namespace.
* Only used when "detectAllHandlerMappings" is turned off.
* @see #setDetectAllHandlerMappings
*/
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";

/** Detect all HandlerMappings or just expect "handlerMapping" bean?. */
private boolean detectAllHandlerMappings = true;

/** List of HandlerMappings used by this servlet. */
@Nullable
private List<HandlerMapping> handlerMappings;

private void initHandlerMappings(ApplicationContext context) {
// 置空 handlerMappings
this.handlerMappings = null;

// <1> 如果开启探测功能,则扫描已注册的 HandlerMapping 的 Bean 们,添加到 handlerMappings 中
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 扫描已注册的 HandlerMapping 的 Bean 们
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
// 添加到 handlerMappings 中,并进行排序
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
// <2> 如果关闭探测功能,则获得 HANDLER_MAPPING_BEAN_NAME 对应的 Bean 对象,并设置为 handlerMappings
} else {
try {
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.
// <3> 如果未获得到,则获得默认配置的 HandlerMapping 类
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");
}
}
}

<1> 处,如果开启探测功能,则扫描已注册的 HandlerMapping 的 Bean 们,添加到 handlerMappings 中。

<2> 处,如果关闭探测功能,则获得 HANDLER_MAPPING_BEAN_NAME( “handlerMapping” ) 对应的 Bean 对象,并设置为 handlerMappings 。

<3> 处,如果未获得到,则调用 #getDefaultStrategies(ApplicationContext context, Class strategyInterface) 方法,获得默认配置的 HandlerMapping 类。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// DispatcherServlet.java

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
// <1> 获得 strategyInterface 对应的 value 值
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
// <2> 创建 value 对应的对象们,并返回
if (value != null) {
// 基于 "," 分隔,创建 classNames 数组
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
// 创建 strategyInterface 集合
List<T> strategies = new ArrayList<>(classNames.length);
// 遍历 classNames 数组,创建对应的类,添加到 strategyInterface 中
for (String className : classNames) {
try {
// 获得 className 类
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
// 创建 className 对应的类,并添加到 strategies 中
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
} catch (ClassNotFoundException ex) {
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
} catch (LinkageError err) {
throw new BeanInitializationException(
"Unresolvable class definition for DispatcherServlet's default strategy class [" +
className + "] for interface [" + key + "]", err);
}
}
// 返回 strategies
return strategies;
} else {
return new LinkedList<>();
}
}

这是个通用的方法,提供给不同的 strategyInterface 接口,获得对应的类型的数组。<1> 处,获得 strategyInterface 对应的 value 值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// DispatcherServlet.java

/**
* Name of the class path resource (relative to the DispatcherServlet class)
* that defines DispatcherServlet's default strategy names.
*/
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

/**
* 默认配置类
*/
private static final Properties defaultStrategies;

static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
// 初始化 defaultStrategies
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
} catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

HandlerMapping 接口,对应的是 BeanNameUrlHandlerMapping 和 RequestMappingHandlerMapping 类。

创建 value 对应的对象们,并返回

1
2
3
4
5
// DispatcherServlet.java

protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
return context.getAutowireCapableBeanFactory().createBean(clazz);
}

然后,我们在回过头看看 DispatcherServlet 对 handlerMappings 的使用,在 #getHandler(HttpServletRequest request) 方法中,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// DispatcherServlet.java

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 遍历 HandlerMapping 数组
for (HandlerMapping mapping : this.handlerMappings) {
// 获得请求对应的 HandlerExecutionChain 对象
HandlerExecutionChain handler = mapping.getHandler(request);
// 获得到,则返回
if (handler != null) {
return handler;
}
}
}
return null;
}