本文基于spring 5.5.2.release
springmvc接收到请求后,第一步要做的事情就是查找Handler,以确定是否可以处理该请求,Handler可以简单的理解为Controller。这个查找的过程是由HandlerMapping完成的。
HandlerMapping是一个接口,实现类必须实现如下方法:
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
springmvc提供了多种不同的HandlerMapping实现类,每个实现类都可以根据请求参数查找对应的Handler。这些实现类实例化对象后都放到DispatcherServlet的属性handlerMappings中,以供后续遍历时查找访问。那这些对象是如何放到属性handlerMappings中的?
文章目录
一、初始化属性handlerMappings
下面是DispatcherServlet的属性handlerMappings的定义:
/** List of HandlerMappings used by this servlet. */
@Nullable
private List<HandlerMapping> handlerMappings;
下面来看一下这个属性是如何初始化的。
DispatcherServlet实现了Servlet接口,因此当第一次外部请求时,会触发该类的init()方法,init()方法最终调用到initHandlerMappings():
//入参context是web环境下的ApplicationContext对象,
//默认实现类是AnnotationConfigServletWebServerApplicationContext
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//detectAllHandlerMappings默认是true,
//表示是自动检测,还是只从容器中查找名字为“handlerMapping”的对象
if (this.detectAllHandlerMappings) {
//下面开始自动查找HandlerMapping对象
//下面这一行代码用于从容器中查找类型为HandlerMapping的对象,
//包括父容器也会一并查找,scope=prototype类型的也会搜索到
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 {
//下面是从容器中查找名字为“handlerMapping”且类型为HandlerMapping的对象
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.
//如果上述过程没有找到HandlerMapping,那么读取文件DispatcherServlet.properties,
//从该文件中加载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");
}
}
}
从上面代码可以看到springmvc直接从容器中获取HandlerMapping对象添加到属性handlerMappings中。那么容器中的对象从哪来?答案是WebMvcConfigurationSupport。WebMvcConfigurationSupport提供了requestMappingHandlerMapping()、viewControllerHandlerMapping()等创建HandlerMapping的方法。该类一共创建四个,分别是:
- RequestMappingHandlerMapping
- BeanNameUrlHandlerMapping
- RouterFunctionMapping
- resourceHandlerMapping
除了上面四个,还有一个是在EnableWebMvcConfiguration中创建的:
- WelcomePageHandlerMapping
有的HandlerMapping对象,指定了order属性,这个属性用于排序使用,可以看到initHandlerMappings()里面也对这些对象做了排序,排序结果如下:
DispatcherServlet遍历HandlerMapping便是以上图的顺序进行,当从其中一个HandlerMapping中找到合适的Handler,那么后面的便不再遍历,下面是遍历的代码,DispatcherServlet便是调用下面这个方法找到合适的Handler:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;//找到后直接返回
}
}
}
return null;
}