Spring MVC源码解析(一)-HandleMapping的注册与发现

Spring MVC是目前主流的WEB MVC框架,许多公司都在使用Spring MVC或者间接的使用Spring MVC。之前一直都是哟Spring MVC但没有具体了解过其实现原理和它的源码实现。
在开始之前,我们先回顾下SpringMVC处理请求的流程:

DispatcherServlet

DispatcherServlet称之为整个SpringMVC最核心的类也不为过,它负责初始化SpringMVC的组件和进行请求的转发。一般在使用Spring MVC时,我们都需要在web.xml配置DispatcherServlet配置方式如下:

1
2
3
4
5
6
7
8
9
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

从上述代码中我们可以知道DispatcherServlet的类路径,我们使用Idea的类图查看工具,查看下DispatcherServlet都实现和继承了哪些接口和类?
DispatcherServlet类图
从上图我们可以看到DispatcherServlet继承了HttpServlet类,HttpServlet中有三个可重写的方法(init()、doService()和destory()),而HttpServletBean重写了init()方法,并最终会调用到DispatchServlet的initStrategies(ApplicationContext context),而这个方法就是Spring MVC初始化组件的地方。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected void initStrategies(ApplicationContext context) {
//初始化上传文件解析器
initMultipartResolver(context);
//初始化本地解析器
initLocaleResolver(context);
//初始化主体解析器
initThemeResolver(context);
//初始化处理器映射器
initHandlerMappings(context);
//初始化处理器适配器
initHandlerAdapters(context);
//初始化处理异常解析器
initHandlerExceptionResolvers(context);
//初始化请求到视图名的解析
initRequestToViewNameTranslator(context);
//初始化视图解析器
initViewResolvers(context);
initFlashMapManager(context);
}

HandleMapping:

HandleMapping是Spring MVC 非常主要的一个模块,Spring MVC通过处理器映射器找到其相关的处理器,并将其封装为处理器适配器,处理器适配器然后执行其handle方法。那么处理器映射器是怎样将request请求和处理方法对应起来,又是怎么找到的。接下来,我们主要看下initHandlerMappings(context)方法,该方法用来初始化处理器映射器。

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
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
/**
*detectAllHandlerMappings是DispatcherServlet的类变量,
*个人认为这个是我们使用new DispatcherServlet()时,可以通过set方法添加,
*但如果使用web.xml时,这个变量是空,因此我们只分析下边else中代码逻辑
*/
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
//在容器中寻找HandleMapping的实现类,并使用工具类将其转换为List集合
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.
}
}

//判断handlerMappings是否为空,如果为空的话,则采用DispatcherServlet.properties中的配置handleMapping
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}

上述方法就是HandleMapping的初始化,首先会判断DispatcherServlet类变量中的handleMappings是否为空,如果为空的话,则从容器中获取,如果容器不存在,则采用默认的处理器射器赋值。默认的处理器器映射器在DispatcherServlet.properties中配置,具体的配置如下:

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

知道了如何初始话处理器映射器,我们接着分析如何通过处理器映射器去寻找到处理器。分析到这里,我们继续回顾下之前说的DispatcherServlet方法是继承了HttpServlet方法,而HttpServlet方法存在三个方法,我们刚才只分析了init()方法来初始化各组件,我们并没有分析doService()方法,在doService方法中调用了一个doDispatch(request, response)方法,该方法就是主要处理请求到处理器以及封装为适配器处理业务逻辑的地方,源码如下:

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {
ModelAndView mv = null;
Exception dispatchException = null;

try {
//检查请求是否含有文件上传
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//获取处理器
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}

applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}

我们通过看代码发现,mappedHandler = getHandler(processedRequest);是获取处理器的主要实现,那么getHandler是怎么实现的呢?

request)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}

首先判断HandlerMappings是否为空,然后遍历HandlerMapping的实现类,通过实现类的getHandler(request)获取到处理器。我们在这里主要分析两个HandMapping的实现类,BeanNameUrlHandlerMapping和RequestMappingHandlerMapping,这两个是默认的处理器映射器。

BeanNameUrlHandlerMapping

BeanNameUrlHandlerMapping类图
我们可以从上图看到BeanNameUrlHandlerMapping实现了ApplicationContextAwre接口,对于单例模式首次调用Bean时,ApplicationContext会查看是否实现了ApplicationContextAwre接口,若实现了则调用setApplicationContext()方法,在ApplicationObjectSupport中的setApplicationContext()方法调用了initApplicationContext(),在类AbstractDetectingUrlHandlerMapping重写了这个方法,具体的代码如下:

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
/**
*调用父类的initApplicationContext()方法,主要是用来初始化MappedInterceptor的实现类
*处理器请求Url和处理器的映射管理,将其处理器注册
*/
@Override
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
detectHandlers();
}

//发现处理器并将其注册
protected void detectHandlers() throws BeansException {
//获取ApplicationContext容器
ApplicationContext applicationContext = obtainApplicationContext();
if (logger.isDebugEnabled()) {
logger.debug("Looking for URL mappings in application context: " + applicationContext);
}
//获取容器中所有的Bean的名称
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
applicationContext.getBeanNamesForType(Object.class));

//遍历Bean,获取Bean中的Url属性配置,并将其注册
for (String beanName : beanNames) {
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
//将该Url对应的Bean进行注册
registerHandler(urls, beanName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
}
}
}
}

在上述代码块中最重要的便是获取容器中的所有bean名称,然后通过遍历容器中的bean名称解析URL,然后调用registerHandler注册URL和beanName对应的Handler。我们继续分析registHandler方法

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
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.
//判断该Handler是否是延迟加载,以及是否是字符串,若不是延迟加载和beanName是字符串类型的,则获取Handler实例
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
ApplicationContext applicationContext = obtainApplicationContext();
if (applicationContext.isSingleton(handlerName)) {
resolvedHandler = applicationContext.getBean(handlerName);
}
}
//从handlerMap中根据url获取Handler实例,如果获取为空,则将其加入handlerMap中。
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 {
//如果bean的url值是/,则将其设置为根处理器
if (urlPath.equals("/")) {
if (logger.isInfoEnabled()) {
logger.info("Root mapping to " + getHandlerDescription(handler));
}
setRootHandler(resolvedHandler);
}
//如果bean的url值是/*,则将其对应的处理器设置为默认的处理器
else if (urlPath.equals("/*")) {
if (logger.isInfoEnabled()) {
logger.info("Default mapping to " + getHandlerDescription(handler));
}
setDefaultHandler(resolvedHandler);
}
else {
//将处理器加入到handleMap对象中,该对象是一个LinkedHashMap对象,用来保存URL和Handler实例的映射关系
this.handlerMap.put(urlPath, resolvedHandler);
if (logger.isInfoEnabled()) {
logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
}
}
}
}

截止这一步,我们分析了Spring MVC的BeanNameUrlHandlerMapping的初始化逻辑,是如何将URL和Handler实例进行管理起来,我们做个小总结在这里:

  1. 首先会判断DispatcherServlet父类中HttpServlet中的init()方法,init()调用其在FrameWorkServlet的initServletBean方法用于初始化WebApplicationContext对象

  2. 初始化完WebApplicationContext对象之后,会调用实现类DispatcherServlet中的onRefresh()方法, onRefresh()方法用于初始化Spring MVC中的组件(文件上传解析组件、本地解析器组件、主题解析器组件、HandlerMapping的实现、HandlerAdapter的实现、异常处理解析组件、请求转换视图解析组件、视图解析器组件以及flash管理组件)。

  3. 其余组件组件就不说了,这里主要说initHandlerMaping方法用于初始化HandlerMapping实现类,如果在环境中未配置,则默认采用BeanNameUrlHandlerMapping和RequestMappingHandlerMapping实现类。

  4. 这一步应该是在在初始化WebApplicationContext实例时,BeanNameUrlHandlerMapping实现类ApplicationContextAwre方法,会在初始化Bean之后调用setApplicationContext方法,setApplicationContext方法调用类子类的detchHanlers方法,用于将配置文件中的URL和Handler关系注册到handlerMap对象中,供之后的getHandler调用。

    这就是BeanNameUrlHandlerMapping的初始化的整个过程,之后我们会介绍获取Handler实例的源码。

RequestMappingHandlerMapping

在分析RequestMappingHandlerMapping之前,我们依照惯例,先看下它的实现图:RequestMappingHandlerMapping类图
我们从上图可以看到RequestMappingHandlerMapping也继承了AbstractHandlerMapping的方法,并且AbstractHandlerMethodMapping类实现了InitializingBean接口,通过实现init()方法来注册HandlerMapping的相关信息,接下来我们就分析init()方法中调用到的initHandlerMethods()方法。

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
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//获取容器中所用的Bean名称
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
//遍历Bean名称,获取对应的Bean类型,判断是否是Handler实现类
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
//获取bean类型
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);
}
}
//判断是否是Handler处理类
if (beanType != null && isHandler(beanType)) {
//如果是Handler的处理类,则处理其中的方法,并将其注册起来
detectHandlerMethods(beanName);
}
}
}
//该方法暂未做任何处理
handlerMethodsInitialized(getHandlerMethods());
}

上述方法就是对RequestMappringHandlerMappting的初始化,其主要的操作包括获取容器中的Bean名称,遍历bean名称,然后获取Bean类型,通过isHandler方法判断是否在类上边含有@Controller或@RequestMapping注解,如果有则返回true,然后调用detectHandlerMethods方法获取其中方法,并做处理与注册。我们继续看detectHandlerMethods方法:

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
protected void detectHandlerMethods(final Object handler) {
//获取bean对应的Class对象,
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());

if (handlerType != null) {
final 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);
}
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
}

上述方法看起来比较复杂,实际上做的处理是获取Bean对应的Class对象,然后获取用户目标类,然后在获取目标类中符合的方法吗,然后将其封装为一个Map<Method, T>的对象,T在这里实际是一个RequestMapptingInfo对象,将RequestMapping转换为一个Java使用的对象数据结构。最后再遍历结果集,调用registerHandlerMethod方法。我们继续看registerHandlerMethod方法:

1
2
3
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}

上述方法没有做过多的处理,而是调用了MappingRegistry的regist方法。

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
public void register(T mapping, Object handler, Method method) {
//在注册时先获取读写锁的写锁,防止其它操作
this.readWriteLock.writeLock().lock();
try {
//将其Handler对象和Method对象包装起来,创建HandlerMethod对象
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);

if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
//该map主要保存RequestMapping对象与HandlerMethod的关联关系
this.mappingLookup.put(mapping, handlerMethod);
//获取RequestMapping对象中的path属性作为Key,RequestMapping对象作为Value进行保存。
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
//根据命名方式获取这个HanderMethod对象的名称,然后再将其保存到名称与HandlerMethod的Map对象中。
String name = null;
if (getNamingStrategy() != null) {
//name值的获取是如果mapping对象中name名称不为空,则直接将mapping中的name属性返回,否则获取HandlerMethod对象中的类名的大写字母+#+method的名称。
name = getNamingStrategy().getName(handlerMethod, mapping);
//将其注入到nameLookup类常量中
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();
}
}

上述方法我们一眼看去,好像注册了许多东西到各自的map对象中,我们来一一讲解他们的作用,首先我们看到会将hanlder对象和method方法创建一个HanlerMethod对象,这个Handlermethod对象在之后一直发挥作用,将mapping信息作为key,HandlerMthod对象作为值来保存到map对象中。其二是解析mapping中的Url信息,将其作为urllookup的键,mapping作为主要信息保存在urlLookup的变量中。其三是保存name和handlerMethod的键值。其四跟踪代码发现corsConfig返回的是个null。最后是将name、mapping、url、hanlerMethod对象包装起来保存。通过上边我们已经知道RequestMappingHandlerMapping是怎样使用到的信息报错起来的。那保存的信息到底如何使用,我们继续回到DispatchServlet对象,去看doDispatch的getHandler方法,getHandler方法调用了getHandlerInternal,getHandlerInternal是一个抽象方法,查找实现方法,发现AbstractHandlerMethodMapping实现了getHandlerInternal方法,具体的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取请求的Url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
//调用具体的根据Url查找HandlerMethod方法,HandlerMethod就是我们上边讲过的对Handler和Method对象的封装。
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}

lookupHandlerMethod方法:

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
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
//Match是Mapping和handlerMethod的封装
List<Match> matches = new ArrayList<>();
//根据Url获取RequestMappingInfo信息,这里实际上调用的就是mappingRegistry中的urllookupPath变量mapping获取到的信息
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//这个方法获取MappingRegistry中mappingLookup获取RequestMappingInfo和HandlerMethood的封装方法放在matches集合中
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
//如果上述的matches为空,则获取MappingRegistry中registry中键集合,即RequestMappingInfo实例集合,然后根据RequestMappingInfo实例信息获取HandlerMethod放到封装起来放到matches集合中
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}

if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
//将其中的Matches根据RequestMappingInfo信息进行排序
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);
handleMatch(bestMatch.mapping, lookupPath, request);
//返回HandlerMethod对象
return bestMatch.handlerMethod;
}
else {
//跟踪代码发现发现返回的是个null
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}

上述代码是获取HandlerMethod对象的主要方法,首先是根据request请求的URL获取到相应的RequestMappingIOnfo对象,然后根据RequestMappingInfo对象获取到相应的HandlerMethod对象,这两个都是之前在将初始化RequestMappingHandlerMapping时放置到MappingRegistry对象中;之后再通过RequestMappingInfo中的比较条件获取到最适合的RequestMappingInfo和HandlerMethod的集合,然后返回其中的HandlerMethod对象。如果没有获取到相应的Match,则返回null。

RequestMappingHandlerMapping小结:RequestMappingHandlerMapping和BeanNameUrlHandlerMapping很相似,都继承了ApplicationContextAwre类,但是其实现方式却不是在setApplicationContext方法中,而是在AbstractHandlerMethodMapping类实现了InitializingBean接口,其中调用了detachHandlerMathods方法,这个方法则是将类中拥有RequestMapping注解的或者Controller注解的方法封装成RequestMappingInfo对象,并获取该注解所在的方法,将其注入到MappingRegistry相应的变量中,供后续使用。而RequestMappingHandlerMapping的getHandler方法也一样通过调用getHandlerInternal方法获取,而具体的获取方法通过AbstractHandlerMethodMapping的lookupHandlerMethod方法实现, 主要是获取根据URI获取MappingRegistry中保存的RequestMappingInfo对象,然后根据RequestMapping对象获取HandlerMethod对象,将其封装为Match,然后通过RequestMappingInfo的比较条件获取到合适的HandlerMethod对象进行返回。

上述就是RequestMappingHandlerMapping的初始化和获取方法,当然写的比较简单,没有对许多具体的方法做相应的解释,但是大家通过看源码就能知道意思,所以也没有在这里做分析。

总结

HandlerMapping(处理器映射器)是了解DisptcherServlet的第一个模块,也是非常重要的模块,通过HandlerMapping我们可以获取到相应的处理器,然后交由HandlerAdapter封装为一个处理器适配器,然后处理器适配器调用handler方法进行业务端的处理返回ModelView对象,然后视图解析器对其做处理返回到前台页面,这次的源码分析就到此……。之后我会继续分析DispatcherServlet的下一个模块-HandlerAdapter,让我们期待……