一句话:这个类主要作用之一是将请求url和对应方法的映射关系缓存起来,方便后续快速路由请求到指定的method
原理
RequestMappingHandlerMapping注入时机
我们要用Springmvc,核心就是用它的DispatcherServlet;DispatcherServlet是一个servlet,它的生命周期受容器控制,即容器在servlet实例化后会调用对应的init方法进行初始化(实际是执行父类 org.springframework.web.servlet.HttpServletBean 的init方法)
方法会执行一系列的初始化动作
这里我们分析一下
org.springframework.web.servlet.DispatcherServlet#initHandlerMappings
这个方法,因为这个方法会注入我们今天的主角类;下面这段代码会将默认的策略类组合赋值给 DispatcherServlet 相应的属性
RequestMappingHandlerMapping分析
- 首先来看下RequestMappingHandlerMapping的继承关系图
这里我最关心也是最重要的一点,它是一个 InitializingBean !!!
这很重要,这表明在类实例化后会自动执行它的 afterPropertiesSet 方法,调用链如下:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#afterPropertiesSet
@Override
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
// @A
super.afterPropertiesSet();
}
- @A:调用父类方法即org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet
@Override
public void afterPropertiesSet() {
//@B
initHandlerMethods();
}
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #isHandler(Class)
* @see #getMappingForMethod(Method, Class)
* @see #handlerMethodsInitialized(Map)
*/
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//@C
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
obtainApplicationContext().getBeanNamesForType(Object.class));
//@D
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
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);
}
}
//@E
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
-
@B:调用 initHandlerMethods 方法
-
@C:根据是否搜索parent容器(false)获得容器中所有的类;(因为这是springmvc项目,只需要搜索当前springmvc容器定义的所有类,准确的说后续只需要接卸controller类)
-
@D:循环遍历beaname获得controller bean
-
@E:执行 isHandler 方法(被 @Controller注解或者被 @RequestMapping注解标注的类会返回true),根据返回值决定是否解析类里面的方法
-
下面我们来到解析url和方法的具体方法 detectHandlerMethods
protected void detectHandlerMethods(final Object handler) {
//@F
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//@G
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);
}
//@H
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
/**
* Register a handler method and its unique mapping. Invoked at startup for
* each detected handler method.
* @param handler the bean name of the handler or the handler instance
* @param method the method to register
* @param mapping the mapping conditions associated with the handler method
* @throws IllegalStateException if another method was already registered
* under the same mapping
*/
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
//@I
this.mappingRegistry.register(mapping, handler, method);
}
-
@F:获得controller类 Class
-
@G:解析controller获得一个Map<Method,RequestMappingInfo>的映射关系,具体封装RequestMappingInfo是子类 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#getMappingForMethod方法
-
@H:循环遍历找到的controller方法,缓存url和方法的关系
-
@I:mapping是RequestMappingInfo对象;handler是controller的类名称(小写开头);method是被@RequestMapping注解标记的方法
-
MappingRegistry是 AbstractHandlerMethodMapping的内部类,我们看看register方法
public void register(T mapping, Object handler, Method method) {
//@J
this.readWriteLock.writeLock().lock();
try {
//@K
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
//@L
this.mappingLookup.put(mapping, handlerMethod);
//@M
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
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);
}
//@N
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
- @J:获得一个写锁
- @K:根据类名和方法封装成一个HandlerMethod对象
- @L:放入RequestMappingInfo为key的map中
- @M:获得方法上声明的url集合,因为 @RequestMapping 注解可以指定多个url;然后缓存到url为key的LinkedMultiValueMap中
- @N:缓存进以RequestMappingInfo为key的 HashMap 中,value是<RequestMappingInfo,方法,注解上标注的url集合,根据策略处理后的方法名>的封装对象
RequestMappingHandlerMapping方法路由
- 一句话:根据J2EE规范处理http请求的方法是 DispatcherServlet的doService方法,核心方法是org.springframework.web.servlet.DispatcherServlet#doDispatch(这个方法是被父类的doService方法调起)
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);
//@A
// 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;
}
}
//@A1
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//@B
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//@C
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);
}
//@D
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);
}
}
}
}
-
@A:根据HttpServletRequest请求对象获得一个 HandlerExecutionChain对象(实际上是对匹配到的HandlerMethod的封装),具体逻辑在org.springframework.web.servlet.DispatcherServlet#getHandler方法,下面我们具体分析
-
@A1:执行拦截器逻辑,这里可见拦截器是在执行真正方法前被执行
-
@B:真正执行HandleMethod的方法,这里是委托给HandlerAdapter(真实实现类是:RequestMappingHandlerAdapter)来执行的,这里会返回一个 ModelAndView
-
@C:设置view的名称,执行一些后置处理
-
@D:处理结果,渲染界面(渲染界面逻辑下一篇文章详细揭秘)
-
接上面@A里分析org.springframework.web.servlet.DispatcherServlet#getHandler方法如何获得HandlerExecutionChain对象
@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,然后调用getHandler方法,如果不为空的话就返回;根据前面的内容我们知道 handlerMappings是2个对象(怎么少了一个?)
+
这里其实起作用的就是上面框架注入的 RequestMappingHandlerMapping,getHandler方法是在它的父类org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler里实现的;
具体调用栈如下:
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
|
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal(根据url找找到之前缓存的元数据信息并封装成 HandlerMethod 对象)
|
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain(将HandlerMethod封装成HandlerExecutionChain对象并返回)
|
最终返回一个 HandlerExecutionChain 对象,传给@B逻辑