这部分应该是SpringMVC的核心,也是我们在平常使用的时候经常会被问到的一个问题,在大学刚接触SpringMVC的时候,经常会看到下面这样的流转图
简单的说一下,就是每一个请求过来的时候,都是由DispatcherServlet进行转发,那么它的第一步就是用过映射处理器(BeanNameUrlHandlerMapping)找到对应的实体类(Controller类),然后再拿这个实体类和每个Adapter进行适配。那么最最重要的,需要理解的,也是就是上一章节说到两个模块:映射处理器和适配器。
由于 DispatcherServlet 继承 FrameworkServlet, Servlet的默认实现doGet,doPost的实现都指向了DispatcherServlet的**doService**方法,在进行doService方法之前,使用了ThreadLocal保存了当前线程的属性
最重要的两个方法:
- 由handlerMapping获取到对应的handler
找到合适的handlerAdapter,然后调用handler方法
/**
* 根据request信息寻找对应的Handler
* private List<HandlerMapping> handlerMappings 是初始化的时候设置 -- initHandlerMappings(context)
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
// 封装处理
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
/**
* 根据URL找到匹配的Controller并且返回,如果当前没有找到对应的Controller处理器,那么程序会尝试查找配置中的默认处理器
* 当然,当查找的controller为String类型的时,那就意味着返回的是配置的bean名称,需要根据bean名称查找对应的Bean,最后还要
* 通过getHandlerExecutionChain()方法对返回的Handler进行封装,以保证满足返回类型的匹配
*/
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据request获取对应的handler
Object handler = getHandlerInternal(request);
if (handler == null) {
// 如果没有对应的request的handler则使用默认的handler
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
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;
}
根据Request查找对应的Handler
(1) 截取用于匹配的url有效路径
(2) 根据路径寻找Handler
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
// 截取用于匹配规则的URL有效路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// 根据路径寻找Handler
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
Object rawHandler = null;
if ("/".equals(lookupPath)) {
// 如果请求的路径仅仅是"/" 那么使用RootHandler处理
rawHandler = getRootHandler();
}
if (rawHandler == null) {
// 如果无法找到handler则使用默认handler
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
if (rawHandler instanceof String) {
// 根据beanName获取对应的Bean
String handlerName = (String) rawHandler;
rawHandler = getApplicationContext().getBean(handlerName);
}
// 模板方法
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
return handler;
}
将Handler封装成HandlerExecutionChain类型,并且加入两个拦截器,这是一个很优秀的设计模式,后面会专门说到
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, Map<String, String> uriTemplateVariables) {
HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
// 加入拦截器
chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
// 加入拦截器
if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
}
return chain;
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
这段代码其实就是将配置的拦截器加入到拦截链中
----