Spring|Spring MVC 02 - HandlerMapping
HandlerMapping
// HandlerMapping
+HandlerExecutionChain getHandler(HttpServletRequest request)
根据 Request 匹配handler 返回
HandlerExecutionChain
。// HandlerExecutionChain
private final Object handler;
private HandlerInterceptor[] interceptors;
HandlerExecutionChain
包含一个实际的handler 和一串interceptors实际常用的实现是
RequestMappingHandlerMapping
。讲Controller 的 @RequestMapping 修饰的方法作为 handler文章图片
image.png
【Spring|Spring MVC 02 - HandlerMapping】AbstractHandlerMapping
HandlerMapping 的入口,管理 handler interceptors. 和一些列工具类
UrlPathHelper
, AntPathMatcher
等。AbstractHandlerMethodMapping
注册handler 和匹配规则,实现根据 request 搜索匹配 handler 的逻辑。T 代表匹配规则。
RequestMappingInfoHandlerMapping
extends AbstractHandlerMethodMapping
将匹配规则实现具体到 RequestMappingInfo 类。同时向请求中添加一些关于解析结果的属性
RequestMappingHandlerMapping
初始化 AbstractHandlerMapping
- initApplicationContext()
detectMappedInterceptors 找到所有mapped interceptor, 添加入adaptedInterceptors list中
afterPropertiesSet()
中调用 initHandlerMethods()
- 遍历所有bean, 使用模版方法
isHandler
判断一个bean 是否为handler。对于handler 调用detectHandlerMethods
detectHandlerMethods()
遍历handler bean 下所有的方法,使用模版方法T getMappingForMethod(Method method, Class> handlerType)
判断并返回当前method 对应的匹配条件。使用registerHandler 注册下来。
registerHandlerMethod(Object handler, Method method, T mapping)
调用MappingRegistry.register()
注册handler 及其mapping.
实现模板方法,检查bean 是否为 Controller 或者 RequestMapping
getMappingForMethod
实现模板方法
- 依次对 handler 和 method 调用 createRequestMappingInfo
2 createRequestMappingInfo 获取 RequestMapping 的 annotation, 调用 createRequestMappingInfo 生成 RequestMappingInfo
3 createRequestMappingInfo 从 RequestMapping 从取出 path, method, header... 加上 config,生成RequestMappingInfo
// 存储匹配条件 - handlerMethod 的 mapping
-Map mappingLookup = new LinkedHashMap();
// 不带匹配规则的简单url - handler methods 的 mapping。方便在查找简单url时快速找到对应的 handler methods
-final MultiValueMap urlLookup = new LinkedMultiValueMap();
register(T mapping, Object handler, Method method)
- 调用 createHandlerMethod(handler, method) 创建 handlerMethod
- 检查该mapping 是否已经注册过
- 加入 mappingLookup
- getDirectUrls 尝试从该mapping 中获取简单url,如有简单url,则加入 urlLookup
//HandlerMapping
HandlerExecutionChain getHandler(HttpServletRequest request)
AbstractHandlerMapping getHandler()
- 调用模版方法 ·Object getHandlerInternal(HttpServletRequest)` 获取 handler
- 调用
getHandlerExecutionChain
. 将handler和所有adaptedInterceptors 添加入 HandlerExectionChain
getUrlPathHelper().getLookupPathForRequest(request)
提取请求路径
- 调用
HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request)
匹配handler
2.1 从urlMap 中尝试直接取出所有满足条件的匹配
2.2 否则则取出所有注册的匹配条件
2.3 模版方法getMatchingMapping 获取准确的mapping 并过滤掉完全不匹配的条件
2.4 用MatchComparator 对所有匹配条件进行排序,找到最佳的。排序算法由模版方法Comparator
提供getMappingComparator(HttpServletRequest request)
2.4 调用模板方法 handleMatch
getMappingComparator()
protected Comparator getMappingComparator(final HttpServletRequest request) {
return (info1, info2) -> info1.compareTo(info2, request);
}
handleMatch()
添加匹配结果相关属性到 request
handleNoMatch()
针对没匹配上的情况抛出相应异常
RequestMappingInfo
文章图片
image.png
- RequestCondition
中的T 是这个匹配条件可以combine/compare 的对象,实际的实现里面都是自己。比如 RequestMappingInfo implements RequestCondition
- getMatchingCondition 返回null (不匹配)或者一个新的 Condition (可以去掉无关的信息)
- compareTo 在执行了 getMatchingCondition 的前提下比较(保证去除了无关信息)
整合了所有请求相关的 Condition
private final PatternsRequestCondition patternsCondition;
private final RequestMethodsRequestCondition methodsCondition;
private final ParamsRequestCondition paramsCondition;
private final HeadersRequestCondition headersCondition;
private final ConsumesRequestCondition consumesCondition;
private final ProducesRequestCondition producesCondition;
private final RequestConditionHolder customConditionHolder;
匹配request 的时候会逐个Condition 检查,都匹配上则通过。
compare 的时候也会逐个Condition 进行比较
总结大致流程
文章图片
image.png
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- spring|spring boot项目启动websocket
- Spring|Spring Boot 整合 Activiti6.0.0
- Spring集成|Spring集成 Mina
- springboot使用redis缓存
- Spring|Spring 框架之 AOP 原理剖析已经出炉!!!预定的童鞋可以识别下发二维码去看了
- Spring|Spring Boot之ImportSelector