DispatcherServlet的初始化流程 讲述DispatcherServlet从Servlet::init一路调用至DispatcherServlet::initStrategies的过程。
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
initHandlerMappings会初始化一些HandlerMapping,在处理请求时,DispatcherServlet会调用getHandler:
// 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;
}
当能获取到HandlerExecutionChain时就返回。@RequestMapping一般对应由RequestMappingHandlerMapping处理。
我们已经知道,@Controller和@RequestMapping是由RequestMappingHandlerMapping处理的,那么它们是如何被收集的呢? RequestMappingHandlerMapping 初始化搜集所有控制器方法的过程分析文章的开头和结尾都总结得很好,但我在此也写下自己的理解(与原文大同小异):
DispatcherServlet::getHandler会一路运行至AbstractHandlerMethodMapping::lookupHandlerMethod,在这里:
Math包含了
private class Match {
private final T mapping;
private final HandlerMethod handlerMethod;
从下文的if (matches.isEmpty())
,结合自己调试可知:
当路径能完美匹配时,比如以下代码匹配/hello/t
:
@RestController
@RequestMapping("/hello")
public class HelloController {
@GetMapping("/t")
public String hello() {
return "this is hello";
}
}
则会执行if (directPathMatches != null) {...}
,如果@GetMapping("/t")
换成@GetMapping("/t*")
,则没有完美路径匹配,会执行if (matches.isEmpty()) {...}
。
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
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);
}
...