1.前言
之前我们springmvc原理篇里已经介绍过,从springmvc核心处理器DispatcherServlet派遣请求的时候,首先会将请求包装,这就是我们这边介绍的HandlerMapping
在springmvc源码介绍中我们知道,HandlerMapping是一个处理对象映射和映射对应的处理程序的一个中间体,它也可以由开发者自己去实现,但是我们一般没有这个必要,因为springmvc框架已经给我们提供了足够的映射处理器给我们,通常在初始化我们的web项目的时候,springmvc会初始化2个处理器:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping、org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,其中RequestMappingHandlerMapping便可以处理我们在Controller中带@RequestMapping的方法,HandlerMapping可以直接实现拦截器,但是不会这么做,通常HandlerMapping都会用一个叫HandlerExecutionChain的东西给包装起来,而HandlerExecutionChain则引入了HandlerInterceptor(拦截器),在包装类中,springmvc已经帮我们处理好了映射对应的handler(处理方法)和拦截器
2.源代码解刨
2.1依赖关系
2.2 源码解刨
DispatcherServlet中首先给当前请求指定对应的HandlerExecutionChain
源码2.2.1
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 || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
//省略代码
}
}
DispatcherServlet提供循环HandlerMapping的方法,将请求包装
源码2.2.2
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
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;
}
在AbstractHandlerMapping(抽象HandlerMapping)中处理了HandlerMapping对应的处理程序,加入拦截器
源码2.2.3
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//处理映射对应的处理程序(所说的控制器)
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 = getApplicationContext().getBean(handlerName);
}
//包装拦截器
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
那么问题来了?HandlerMapping如何处理带@RequestMapping的方法?
springmvc很机制,直接将两个类的字母连接起来形成一个叫RequestMappingHandlerMapping,RequestMappingHandlerMapping依赖RequestMappingInfoHandlerMapping、RequestMappingInfoHandlerMapping依赖AbstractHandlerMethodMapping(看依赖图),在AbstractHandlerMethodMapping中的一个内部类MappingRegistry中,通过注册方法,直接将
@RequestMappng中包含的信息RequestMappingInfo和HandlerMethod通过LinkedHashMap(key-value)方式连接,也就是说有了RequestMapping(RequestMappingInfo)就能得到HandlerMethod(看源码2.2.7)HandlerMethod包装了执行类、执行方法、参数、桥接处理器
源码2.2.4
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//获取url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
//根据url获取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 + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
源码2.2.5
//查找当前请求的最优处理方法。如果找到多个匹配,选择最佳匹配。
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
//mappingRegistry注册器
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
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));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + 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 + "}");
}
}
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
源码2.2.6
注册器注册了映射和HandlerMethod的关系,并且使得后续适配器中得到适配
源码2.2.7
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
//将requestMappingInfo和handlerMethod绑定
this.mappingLookup.put(mapping, handlerMethod);
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);
}
this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
3.小结
到此为止,springmvc已经将请求包装处理好,也就是对应第一张原理图中的如下标记是2、3的部分
期待下一章HandlerAdapter
发现一个机智的导航😳
来源:oschina
链接:https://my.oschina.net/u/1258171/blog/717004