这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战
介绍
HandlerAdapter
是Handler
的适配器,每种类型的Handler
都对应一个HandlerAdapter
,用于在获取到具体的逻辑处理器进行一些相关数据的转换,比如对参数列表的转换、对处理器处理的返回值的数据转换,不同容器下异步相关的处理等等。
分析
在顶层接口HandlerAdapter
的实现中,基本上都是直接具体的实现。
HandlerAdapter
有几个比较重要的接口:
supports
:当前HandlerAdapter
是否支持这个Handler
handle
:利用Handler
处理请求
这里以AbstractHandlerMethodAdapter
为例进行分析。这个抽象类也比较简单,仅仅是将顶层接口中的参数进行具象化,再调用本类的模板方法,供子类直接使用,所以子类就不需要在进行类型相关的装换等操作。
如果handler
是HandlerMethod
, 直接强转后调用模板方法。
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
通过上述的转换进入到这个扩展接口,这是个抽象方法,由子类具体进行实现。
protected abstract boolean supportsInternal(HandlerMethod handlerMethod);
处理请求接口:这里仅仅是将处理器的类型转换为处理器顶层接口类型后,就直接调用开放接口,具体的实现也是由子类实现。
public final ModelAndView handle(HttpServletRequest rq, HttpServletResponse rs, Object h) throws Exception {
return handleInternal(rq, rs, (HandlerMethod) h);
}
RequestMappingHandlerAdapter
是HandlerAdapter
体系中最复杂的类,包含了具体Handler
执行前后需要特殊处理或者是一些开放的扩展点的处理。比如有参数处理器、参数名称处理器、请求消息体装换器、结果处理器等等。
1.初始化
RequestMappingHandlerAdapter
的初始化分为两步,一步是在构造函数中进行默认HttpMessageConvert
的添加,另一步是通过afterPropertiesSet
后置初始化方法进行一些全局处理的缓存和一些组件的初始化。
- 初始化全局的三个缓存变量。
- 初始化参数解析器,以下获取接口中定义了一些常用的参数解析器,同时支持添加用户自定义参数解析器
- 初始化
initBinder
注解标记的方式参数绑定处理器,以下获取接口方法中可以获取到默认的解析器,同时支持添加用户自定义参数绑定器 - 初始化返回值处理器
returnValueHandlers
,以下方法获取可以获取到返回值解析器,同时支持添加用户自定义返回值处理器。
public void afterPropertiesSet() {
// 1.
initControllerAdviceCache();
// 2.
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//3.
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//4.
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
初始化全局的三个参数解析器的缓存modelAttributeAdviceCache
、initBinderAdviceCache
、requestResponseBodyAdvice
。先从容器中获取出带有ControllerAdvice
注解标记的所有容器对象。然后遍历这些对象,逐个对ModelAttribute
注解、InitBinder
注解,或者是RequestBodyAdvice
或者是ResponseBodyAdvice
的实现类的判断,然后分别添加到三个缓存器的添加处理。
- 若在上述解析过程中存在实现类, 则添加到最前面, 所以在
requestResponseBodyAdvice
中, 自定义的优先级高于默认
private void initControllerAdviceCache() {
// ...
// 1.
if (!requestResponseBodyAdviceBeans.isEmpty()) {
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
}
2.实际处理
实际上核心处理在invokeHandlerMethod
中,先对一些组件进行创建和赋值、初始化各种组件之后将数据传入invokeAndHandle()
中。
protected ModelAndView invokeHandlerMethod(HttpServletRequest r, HttpServletResponse rs, HandlerMethod h) throws Exception {}
获取创建WebDataBinder
实例的工厂类,其中WebDataBinder
类用于绑定request
参数到JavaBean
对象,然后获取@ModelAttribute
的非@RequestMapping
方法,ServletInvocableHandlerMethod
是继承于HandlerMethod
这里相当于只是将handlerMethod
中的属性值赋值给invocableMethod
, 仅仅只做了包了一层,接着就是为ServletInvocableHandlerMethod
中的一些数据赋值, 增加了参数解析、处理器方法调用、返回值解析等逻辑,创建各种参数名称处理器、视图处理器、还有一些异步请求相关的处理。最后构建ModelAndView
实例返回。
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
//
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
ServletInvocableHandlerMethod
就是具体的HandlerMethod
的实现,所以在最后通过invocableMethod.invokeAndHandle(webRequest, mavContainer)
调用到具体的实现。以下基本上就是具体Handler
的调用前最后一步了,返回执行结果之后,由结果处理器进行处理。
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//..
}
// 执行调用逻辑(这里会先经过参数解析器的处理之后,再通过反射调用到具体的方法)
invokeForRequest(webRequest, mavContainer, providedArgs);
进入返回值处理器进行相关处理
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
这里想简要说明一下异步调用的场景:Servlet3.0
支持服务器异步操作,在springmvc
中也添加了响应的支持。整个请求的过程与同步类似,只是在具体的handler
调用之后,如果是异步方式,假设是使用Callable
,则这里获取到的返回值处理器就是CallableMethodReturnValueHandler
。通过使用Callable
方式异步处理逻辑。
WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);
进入到返回值处理器CallableMethodReturnValueHandler
后,将结果的callable
对象使用webAsyncUtils
进行异步处理。通过webAsyncTask.getExecutor()
获取对应线程池。
-
默认情况下会创建
DEFAULT_TASK_EXECUTOR
->SimpleAsyncTaskExecutor
线程池 -
一般来说, 在
RequestMappingHandlerAdapter
中, 创建的WebAsyncManager
时会传入它的this.taskExecutor
2.1 而
RequestMappingHandlerAdapter
也会创建一个默认的SimpleAsyncTaskExecutor
(名称前缀为MvcAsync
) 2.1.1 如果是在
springmvc
中, 初始化Bean
的RequestMappingHandlerAdapter
时为它添加了单一线程池Executor.newSingleThreadExecutor
2.1.2 如果是在
springboot
中, 初始化Bean
的RequestMappingHandlerAdapter
时为它添加了一个名为applicationTaskExecutor
的线程池
创建线程池对象,设置对应的拦截器,获取到具体的callable
对象,创建拦截器链对象, 拦截器链对象一般情况下都会包含拦截列表、具体执行对象以及具体执行到某个拦截器的下标值,分别设置超时处理器、错误处理器、正常完成处理器,再设置一些标志位后将callable
对象丢入线程池中,最后执行完成之后进行结果的分发, 这个具体在不同容器有不同的实现(tomcat
、undertow
)
总结
实际上处理器适配器就是一种适配器,所以每一种的处理器都需要配备一个适配器。它根据特殊的规则找到具体的处理器,是映射器与处理器之间的桥梁。