spring源码:getHandler和getHandlerAdapter
getHandler
准备好HandlerMapping列表后,继续DispatcherServlet的doDispatch方法 -> getHandler方法,根据当前HttpServletRequest(其实当前为其子类型RequestFacade)适配具体要调用的Controller方法和需要执行的拦截器链,如下:
@Nullable
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;
}
遍历所有的初始化的HandlerMapping列表,如果匹配到就进行返回。当前只分析常用的@RequestMapping注解方式,匹配到则会调用RequestMappingHandlerMapping的实现的mapping.getHandler方法,功能如下:
- 匹配需要调用的方法对象(HandlerMethod)
- 如果没有获取到,赋值默认的操作器(默认为null)
- 如果被执行的调用类型为String,则认为是BeanFactory中Bean的名称,获取返回
- 获取当前请求的拦截器(HandlerInterceptor)执行链,和handler绑定,并且内部获取所有的拦截器,并组装HandlerExecutionChain(HandlerMethod和HandlerInterceptor调用链)
- 如果设置了跨域,配置跨域信息并放入handler中
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 匹配需要调用的方法对象(HandlerMethod)
Object handler = getHandlerInternal(request);
// 如果没有获取到,赋值默认的操作器
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// 如果被执行的调用类型为String,则认为是BeanFactory中Bean的名称,获取返回
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 获取当前请求的拦截器(HandlerInterceptor)执行链
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// 对cors跨域方式的处理
if (hasCorsConfigurationSource(handler)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
getHandlerAdapter
handlerAdapters 在初始化九大组件的时候已经完成,默认配置在DispatcherServlet.properties文件中
能否适配主要取决于适配器的supports方法如何实现
默认适配器有如下三个
- HttpRequestHandlerAdapter
- SimplerControllerHandlerAdapter
- RequestMappingHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter adapter = (HandlerAdapter)var2.next();
if (adapter.supports(handler)) {
return adapter;
}
}
}
一个请求执行过程
首先找到 DispatcherServlet ,打开这个 Servlet 的继承体系结构
作为一个 Servlet 必然有 doGet / doPost 方法,在 HttpServletBean 中没有找到,那么继续尝试去子类中找,打开 FrameworkServlet,在这个 Servlet 中我们找到了 doGet 和 doPost 方法
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
FrameworkServlet 中的 doGet / doPost 方法最终调用的都是本类的 processRequest 方法,点进去 processRequest 方法,里面有核心的业务方法 doService(request, response)
打开 doService 方法,发现该方法是一个抽象方法
protected abstract void doService(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
打开 doService 方法的实现类,我们就来到了 DispatcherServlet 这个类中,它作为 FrameworkServlet 的子类,重写了 FrameworkServlet 的抽象方法 doService
打开 DispatcherServlet 的 doService 方法,里面有该 Servlet 的核心方法 doDispatch(request, response)
打开 doDispatch 方法,里面有一个 mappedHandler = getHandler(processedRequest) 方法,该方法的作用是根据请求路径获取匹配的处理器执行链
例如
浏览器发送请求 http://localhost:8080/user/1/games/dota ,就会匹配到 MvcController 这个控制器的 requestParams 方法
// 该注解是 @Controller 和 @ResponseBody 的组合注解
// @Controller:表明该类是一个 Controller ,它的底层是 @Component 注解,会将该类注入到 IOC 容器中
// @ResponseBody:将 Controller 类中方法的返回值对象通过适当的转换器转换之后,写入到 Response 对象的 body 区(响应体中)
// 通常用来返回 JSON 或者是 XML 数据
@RestController
public class MvcController {
// 该注解等价于 @RequestMapping(value="/user/{1}/games/{dota}",method = RequestMethod.GET)
// Rest 风格获取 1 号用户最喜欢玩的游戏
@GetMapping(value="/user/{userId}/games/{favGame}")
public Map<String, Object> requestParams(
// 将路径变量中的 userId 赋值给形式参数 id
@PathVariable("userId") Integer id,
// 将路径变量中的 favGame 赋值给形式参数 favouriteGame
@PathVariable("favGame") String favouriteGame) {
Map map = new HashMap<String, Object>();
map.put("id", id);
map.put("favouriteGame", favouriteGame);
return map;
}
}
代码块一、getHandler(processedRequest)
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 1、获取 Springboot 默认为我们注入的所有 handlerMappings ,它的作用是保存 request 和 handler 的映射规则
if (this.handlerMappings != null) {
// 2、循环遍历所有的 handlerMappings ,
for (HandlerMapping mapping : this.handlerMappings) {
// 3、获取 handler ----> 详情见代码块二
HandlerExecutionChain handler = mapping.getHandler(request);
// 4、如果能找到合适的 handler ,将该处理器返回
if (handler != null) {
return handler;
}
}
}
// 5、如果没有找到合适的处理器,返回 null
return null;
}
1、handlerMappings: Springboot 为我们默认配置的 handlerMappings 如下
所有的 mapping 映射关系保存在 mappingRegistry (映射注册中心) 中,具体的 @RequestMapping 注解与其处理器映射关系如下
3、获取 handler: 获取处理器 handler 并将其封装在处理器执行链中(HandlerExecutionChain 封装 handler 和 interceptors) ----> 详情见代码块八
代码块二、mapping.getHandler(request)中的getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 1、获取内部的处理器 ----> 详情见代码块三
Object handler = getHandlerInternal(request);
// 2、如果没有定义处理器,则获取默认的处理器(默认的处理器为 null,难道是需要我们自己设置一个默认的处理器吗?)
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 3、获取处理器执行链 ----> 代码块六
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
// 4、与跨域访问有关
if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
// 5、返回处理器执行链
return executionChain;
}
1、getHandlerInternal(request):获取内部的处理器 ----> 详情见代码块三
3、getHandlerExecutionChain:获取处理器执行链 ----> 代码块六
代码块三、getHandlerInternal
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 1、移除可生产的媒体类型属性值
request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
try {
// 2、调用父类的 getHandlerInternal 方法 ----> 详情见代码块四
return super.getHandlerInternal(request);
}
finally {
// 3、清除媒体类型属性
ProducesRequestCondition.clearMediaTypesAttribute(request);
}
}
代码块四、super.getHandlerInternal(request)中的getHandlerInternal
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 1、通过 UrlPathHelper 获取 request 请求中的请求路径(浏览器或其它客户端发送的请求路径 user/1/games/dota
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// 2、将获取到的请求路径作为属性设置到 request 中
request.setAttribute(LOOKUP_PATH, lookupPath);
// 3、读锁
this.mappingRegistry.acquireReadLock();
try {
// 4、获取处理器方法 ----> 详情见代码块五
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// 5、返回最终的处理器方法(也就是哪个 Controller 中的哪个方法能处理该请求)
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
// 6、释放锁
this.mappingRegistry.releaseReadLock();
}
}
代码块五、寻找处理器方法:lookupHandlerMethod
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
// 1、定义一个 List 集合 matches
List<Match> matches = new ArrayList<>();
// 2、根据请求路径查询有没有能直接匹配上的,如果有,则将其存入 directPathMatches 集合中
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
// 3、如果直接匹配上了,则添加到 matches 集合中
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
// 4、如果没有直接匹配上,则获取所有的映射,挨个匹配
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
// 5、匹配、排序、筛选出最匹配的处理方法
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
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();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
// 6、将获取的最佳处理方法设置为 request 的属性
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
// 7、处理具体的匹配
handleMatch(bestMatch.mapping, lookupPath, request);
// 8、返回最佳的匹配方法
return bestMatch.handlerMethod;
}
else {
// 9、如果所有的 mappings 都没有任何一个能匹配上,返回 null
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
2、直接匹配,比如浏览器输入 http://localhost:8080/user/1/games/dota ,它会寻找有没有 @RequestMapping(“/user/1/games/dota”,…) 这个内容的注解
8、通过 /user/1/games/dota 寻找到最佳的匹配方法如下
代码块六、getHandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 1、判断当前 handler 是否是 HandlerExecutionChain 类型,如果不是则新建一个 HandlerExecutionChain
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 2、获取请求路径
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 3、如果处理器拦截器是已经映射过的拦截器
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
// 4、处理器执行链添加拦截器
chain.addInterceptor(interceptor);
}
}
// 5、返回处理器执行链
return chain;