1. HandlerAdapter 概述
在 SpringMVC 中Handler可以是各种类型的类, 而DispatcherServlet肯定需要对 handler 进行激活, 所以这时需要一个适配类, 将各种handler适配成可以执行的类, 这时 HandlerAdapter就出现了; 主要代码如下
// Handler 处理适配器, 适配不同的 Handler
public interface HandlerAdapter {
/** HandlerAdapter 是否支持这个 handler <-- 通常是检查这个 handler 是否是某一类
* 如
* SimpleServletHandlerAdapter --> javax.servlet.Servlet
* SimpleControllerHandlerAdapter --> org.springframework.web.servlet.mvc.Controller
* HttpRequestHandlerAdapter --> org.springframework.web.HttpRequestHandler
* RequestMappingHandlerAdapter --> handler instanceof HandlerMethod
* PS: 整个 DispatcherServlet 的入口是 HandlerAdapter.handle, 但其中真正执行的可能是 Servlet, Controller, HttpRequestHandler, HandlerMethod; 这时就需要 HandlerAdapter 来进行适配操作
*/
boolean supports(Object handler);
// 处理 HttpServletRequest 的入口方法
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
// Http 请求中的lastModifiedTime, 默认 -1
long getLastModified(HttpServletRequest request, Object handler);
}
而 HandlerAdapter具有如下子类:
1. SimpleServletHandlerAdapter: 适配实现 Servlet 接口的 Handler, 默认调用其 service 方法
2. SimpleControllerHandlerAdapter: 适配实现 Controller 接口的 Handler, 默认调用其 handleRequest 方法
3. HttpRequestHandlerAdapter: 适配实现 HttpRequestHandler 接口的 Handler, 默认调用其 handleRequest 方法
4. RequestMappingHandlerAdapter: 适配被@RequestMapping注释的方式, 一般都是解析一个一个参数, 并且通过反射进行激活
PS: 上面几个子类中只有 RequestMappingHandlerAdapter有复杂的逻辑, 也是使用最频繁的 HandlerAdapter
2. HandlerAdapter 的子类 SimpleServletHandlerAdapter
SimpleServletHandlerAdapter 适配 Servlet 调用的HandlerAdapter, 代码如下:
public boolean supports(Object handler) {
return (handler instanceof Servlet); // 只要是个 Servlet, 就支持
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 直接调用 Servlet 的 service 接口返回
((Servlet) handler).service(request, response);
return null;
}
3. HandlerAdapter 的子类 SimpleControllerHandlerAdapter
SimpleControllerHandlerAdapter 适配 Controller 接口的 HandlerAdapter, 代码如下:
public boolean supports(Object handler) {
// 判断将要调用的 handler 是不是 Controller
return (handler instanceof Controller);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 调用 Controller 接口类的接口方法 handleRequest() 方法直接响应给前端
return ((Controller) handler).handleRequest(request, response);
}
4. HandlerAdapter 的子类 HttpRequestHandlerAdapter
HttpRequestHandlerAdapter 适配 HttpRequestHandler 的 HandlerAdapter, 代码如下:
public boolean supports(Object handler) {
// 判断将要调用的 handler 是不是 HttpRequestHandler
return (handler instanceof HttpRequestHandler);
}
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 调用 HttpRequestHandler 接口类的接口方法 handleRequest() 方法直接响应给前端
((HttpRequestHandler) handler).handleRequest(request, response);
return null;
}
5. RequestMappingHandlerAdapter 概述
RequestMappingHandlerAdapter 将被@RequestMapping注释修饰的方法封装成ServletInvocableHandlerMethod, 并进行激活, 其主要有如下组件:
// 参数解析器 HandlerMethodArgumentResolver, 比如 RequestResponseBodyMethodProcessor
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
// 组合模式的参数解析器
private HandlerMethodArgumentResolverComposite argumentResolvers;
// initBinderArgumentResolvers 的 参数解析器
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
// 返回值处理器 比如 RequestResponseBodyMethodProcessor
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
// 组合模式的 返回值解析器
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
// ModelAndView 解析器
private List<ModelAndViewResolver> modelAndViewResolvers;
// 内容解析器 <-- 一般通过 HttpServletRequest 获取 MediaType
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
// HttpMessageConverter 转换器 --> 比如 form 表单的 FormHttpMessageConverter, Json 对应的 MappingJackson2HttpMessageConverter
private List<HttpMessageConverter<?>> messageConverters;
// request|response 对应的 Advice <-- 其实就像 AOP 中的 Advice的概念
private List<Object> requestResponseBodyAdvice = new ArrayList<Object>();
// 是否给予 Session 同步请求
private boolean synchronizeOnSession = false;
// Session 中存储|获取器
private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
// 方法解析器, 默认使用 ASM | 反射来获取 <- 反射针对 Java 8
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
// BeanFactory
private ConfigurableBeanFactory beanFactory;
上面每个组件都有其对应的作用: 其中主要有 HandlerMethod 的参数解析器HandlerMethodArgumentResolver, 返回值处理器 HandlerMethodReturnValueHandler, 请求内容的格式解析器 ContentNegotiationManager, 知道了请求内容的格式,这时需要将字符串转为对应方法参数的参数转换器 HttpMessageConverter, Controller增强器 requestResponseBodyAdvice(这其实就像Aop中的Advice), 再者我们可以通过 @RequestParam 获取指定名称的参数内容, 所以还需要一个参数名称获取器 ParameterNameDiscoverer(有基于ASM, 有基于反射机制); 首先我们来看一下 RequestMappingHandlerAdapter 的初始化, 对应的初始化入口在 InitializingBean.afterPropertiesSet 中进行:
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
// 初始化 被 @ControllerAdvice 修饰的类 <-- 这是一个 Controller 增强器, 主要是通过 @ModelAttribute, @InitBinder 注解
initControllerAdviceCache();
// 初始化 HandlerMethodArgumentResolver, 最后封装成 HandlerMethodArgumentResolverComposite <-- 组合模式
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); // Spring 里面 composite 模式 的提现
}
// 初始化 参数绑定方法的参数解决器 <-- 这个平时用得比较少
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 初始化 HandlerMethodReturnValueHandler 比如 -> RequestResponseBodyMethodProcessor
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
其上主要还是做了:
1. 初始化 被 @ControllerAdvice 修饰的类 <-- 这是一个 Controller 增强器, 主要是通过 @ModelAttribute, @InitBinder 注解
1.1 收集 ApplicationContext 中所有被 @ControllerAdvice 注解修饰的 Bean, 并封装成 ControllerAdviceBean
1.2 获取 Bean 上被 @ModelAttribute @RequestMapping 修饰的方法
1.3 将被 @ModelAttribute @RequestMapping 修饰的方法 放入 modelAttributeAdviceCache
1.4 获取 Bean 上被 @InitBinder 注解的方法, 并放入 initBinderAdviceCache 中
1.5 若是 RequestBodyAdvice 子类, 则加入 requestResponseBodyAdviceBeans
1.6 若是 RequestBodyAdvice 子类, 则加入 requestResponseBodyAdviceBeans
2. 初始化 HandlerMethodArgumentResolver(这里主要分成 基于注解的参数解决器, 基于参数类型的解决器), 最后封装成 HandlerMethodArgumentResolverComposite <-- 组合模式
3. 初始化 参数绑定方法的参数解决器(这里主要分成 基于注解的参数解决器, 基于参数类型的解决器), 最后封装成 HandlerMethodArgumentResolverComposite <-- 组合模式 <-- 这个平时用得比较少
4. 初始化 HandlerMethodReturnValueHandler(这里主要分成 基于注解的参数解决器, 单|多个目的的解决器) 比如 -> RequestResponseBodyMethodProcessor, 最后封装成 HandlerMethodReturnValueHandlerComposite <-- 组合模式
上面的参数解析器其实在 SpringMVC 中扮演着非常重要的角色, 也是 SpringMVC 扩展点的一个体现机制, 主要用到了如下的解析器:
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { // 获取默认的 HandlerMethodArgumentResolver
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
// 基于注解的参数解析 <-- 解析的数据来源主要是 HttpServletRequest | ModelAndViewContainer
// Annotation-based argument resolution
// 解析被注解 @RequestParam, @RequestPart 修饰的参数, 数据的获取通过 HttpServletRequest.getParameterValues
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
// 解析被注解 @RequestParam 修饰, 且类型是 Map 的参数, 数据的获取通过 HttpServletRequest.getParameterMap
resolvers.add(new RequestParamMapMethodArgumentResolver());
// 解析被注解 @PathVariable 修饰, 数据的获取通过 uriTemplateVars, 而 uriTemplateVars 却是通过 RequestMappingInfoHandlerMapping.handleMatch 生成, 其实就是 uri 中映射出的 key <-> value
resolvers.add(new PathVariableMethodArgumentResolver());
// 解析被注解 @PathVariable 修饰 且数据类型是 Map, 数据的获取通过 uriTemplateVars, 而 uriTemplateVars 却是通过 RequestMappingInfoHandlerMapping.handleMatch 生成, 其实就是 uri 中映射出的 key <-> value
resolvers.add(new PathVariableMapMethodArgumentResolver());
// 解析被注解 @MatrixVariable 修饰, 数据的获取通过 URI提取了;后存储的 uri template 变量值
resolvers.add(new MatrixVariableMethodArgumentResolver());
// 解析被注解 @MatrixVariable 修饰 且数据类型是 Map, 数据的获取通过 URI提取了;后存储的 uri template 变量值
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
// 解析被注解 @ModelAttribute 修饰, 且类型是 Map 的参数, 数据的获取通过 ModelAndViewContainer 获取, 通过 DataBinder 进行绑定
resolvers.add(new ServletModelAttributeMethodProcessor(false));
// 解析被注解 @RequestBody 修饰的参数, 以及被@ResponseBody修饰的返回值, 数据的获取通过 HttpServletRequest 获取, 根据 MediaType通过HttpMessageConverter转换成对应的格式, 在处理返回值时 也是通过 MediaType 选择合适HttpMessageConverter, 进行转换格式, 并输出
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
// 解析被注解 @RequestPart 修饰, 数据的获取通过 HttpServletRequest.getParts()
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
// 解析被注解 @RequestHeader 修饰, 数据的获取通过 HttpServletRequest.getHeaderValues()
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
// 解析被注解 @RequestHeader 修饰且参数类型是 Map, 数据的获取通过 HttpServletRequest.getHeaderValues()
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
// 解析被注解 @CookieValue 修饰, 数据的获取通过 HttpServletRequest.getCookies()
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
// 解析被注解 @Value 修饰, 数据在这里没有解析
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
// 解析被注解 @SessionAttribute 修饰, 数据的获取通过 HttpServletRequest.getAttribute(name, RequestAttributes.SCOPE_SESSION)
resolvers.add(new SessionAttributeMethodArgumentResolver());
// 解析被注解 @RequestAttribute 修饰, 数据的获取通过 HttpServletRequest.getAttribute(name, RequestAttributes.SCOPE_REQUEST)
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
// 解析固定类型参数(比如: ServletRequest, HttpSession, InputStream 等), 参数的数据获取还是通过 HttpServletRequest
resolvers.add(new ServletRequestMethodArgumentResolver());
// 解析固定类型参数(比如: ServletResponse, OutputStream等), 参数的数据获取还是通过 HttpServletResponse
resolvers.add(new ServletResponseMethodArgumentResolver());
// 解析固定类型参数(比如: HttpEntity, RequestEntity 等), 参数的数据获取还是通过 HttpServletRequest
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
// 解析固定类型参数(比如: RedirectAttributes), 参数的数据获取还是通过 HttpServletResponse
resolvers.add(new RedirectAttributesMethodArgumentResolver());
// 解析固定类型参数(比如: Model等), 参数的数据获取通过 ModelAndViewContainer
resolvers.add(new ModelMethodProcessor());
// 解析固定类型参数(比如: Model等), 参数的数据获取通过 ModelAndViewContainer
resolvers.add(new MapMethodProcessor());
// 解析固定类型参数(比如: Errors), 参数的数据获取通过 ModelAndViewContainer
resolvers.add(new ErrorsMethodArgumentResolver());
// 解析固定类型参数(比如: SessionStatus), 参数的数据获取通过 ModelAndViewContainer
resolvers.add(new SessionStatusMethodArgumentResolver());
// 解析固定类型参数(比如: UriComponentsBuilder), 参数的数据获取通过 HttpServletRequest
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
上面的解析器主要分成基于注解, 基于参数类型, 与自定义的参数解析器(PS: 大体上的数据来源是 HttpServletRequest的 header|body 中的属性, ModelAndViewContainer)! 然后就是处理返回值的处理器:
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
// Single-purpose return value types
// 支持 ModelAndView 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 ModelAndViewContainer
handlers.add(new ModelAndViewMethodReturnValueHandler());
// 支持 Map 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 ModelAndViewContainer
handlers.add(new ModelMethodProcessor());
// 支持 View 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 ModelAndViewContainer
handlers.add(new ViewMethodReturnValueHandler());
// 支持 ResponseEntity 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 HttpServletResponse 的数据流中 OutputStream
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
// 支持 ResponseEntity | StreamingResponseBody 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 HttpServletResponse 的数据流中 OutputStream
handlers.add(new StreamingResponseBodyReturnValueHandler());
// 支持 HttpEntity | !RequestEntity 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 HttpServletResponse 的数据流中 OutputStream
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));
// 支持 HttpHeaders 类型的 HandlerMethodReturnValueHandler, 最后将数据写入 HttpServletResponse 的数据头部
handlers.add(new HttpHeadersReturnValueHandler());
// 支持 Callable 类型的 HandlerMethodReturnValueHandler
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
// 支持 WebAsyncTask 类型的 HandlerMethodReturnValueHandler
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
// 将数据加入 ModelAndViewContainer 的 HandlerMethodReturnValueHandler
handlers.add(new ModelAttributeMethodProcessor(false));
// 返回值被 ResponseBody 修饰的返回值, 并且根据 MediaType 通过 HttpMessageConverter 转化后进行写入数据流中
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
// 支持返回值为 CharSequence 类型, 设置 ModelAndViewContainer.setViewName
handlers.add(new ViewNameMethodReturnValueHandler());
// 支持返回值为 Map, 并将结果设置到 ModelAndViewContainer
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ModelAttributeMethodProcessor(true));
}
return handlers;
}
在有了这些工具类后, 我们就可以完成AbstractHandlerMethodAdapter中定义的抽象方法handleInternal, 在 handleInternal 中主要进行了并发的控制(并发的粒度是 HttpSession), 而正真的方法激活交给了 ServletInvocableHandlerMethod, 对 ServletInvocableHandlerMethod 的初始化在 invokeHandlerMethod 中:
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 构建 ServletWebRequest <-- 主要由 HttpServletRequest, HttpServletResponse
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 构建 DataBinder 工厂
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// binderFactory 中存储着被 @InitBinder, @ModelAttribute 修饰的方法 <- 最终包裹成 InvocableHandlerMethod
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 构建一个 ServletInvocableHandlerMethod
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 设置方法参数解析器 HandlerMethodArgumentValueResolver
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
// 返回值处理器 HandlerMethodReturnValueHandler
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
// 设置 WebDataBinderFactory
invocableMethod.setDataBinderFactory(binderFactory);
// 设置 参数名解析器
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 获取 HttpServletRequest 中存储的 FlashMap
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 这里是激活 @ModelAttribute, @InitBinder 方法, 并将返回值放入 ModelAndViewContainer
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 将 HttpServletRequest 转换成方法的参数, 激活方法, 最后 通过 HandlerMethodReturnValueHandler 来处理返回值
invocableMethod.invokeAndHandle(webRequest, mavContainer);
// 生成 ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted(); // 标志请求已经结束, 进行一些生命周期回调函数的激活
}
}
代码到这边HandlerMethod还是没有激活, 还有非常重要的工作需要去做 -> 参数的解析与绑定 + 反射激活方法 + 返回值处理; 参数解析 + 绑定的操作在 InvocableHandlerMethod中, 具体流程如下:
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {
// 这里的 getMethodParameters 其实是在构造 MethodParameters 时创建的
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
// 从这里开始对参数进行一个一个解析 <- 主要是通过 HandlerMethodArgumentResolver
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
// 设置参数名解析器 ParameterNameDiscoverer (默认通过 ASM)
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
// 这一步是尝试 判断 参数 providedArgs 里面的类型是否满足 parameter
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) continue;
// 判断是否 argumentResolvers 里面含有对应的 解释器
if (this.argumentResolvers.supportsParameter(parameter)) {
try { // 通过 argumentResolvers 解析 HandlerMethod 里面 对应的参数内容
args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {throw ex;}
}
}
return args;
}
再得到参数后其实就可以激活对应的方法, 而返回值的做法相对上面的参数解析要简单一点, 都是先获取对应的返回值处理, 然后进行处理!
6. HandlerAdapter 中的优秀设计
1. 模版模式: 比如在 AbstractHandlerMethodAdapter中的 handleInternal, 而正真的实现在RequestMappingHandlerAdapter
2. 策略模式: 根据不同的策略实现接口 HandlerAdapter, 以支持不同的"controller"
3. InitializingBean: 这是 BeanFactory 中Bean生命周期的扩展接口, 表示 Bean 的初始化方法, RequestMappingHandlerAdapter 就是通过这个接口实现工具类的初始化
4. MethodIntrospector: 这是一个对方法进行反省操作的工具类, 通过传入 classType 与 methodFilter 来过滤需要的 Method
7. 总结
HandlerAdapter 是 SpringMVC中扩展机制的非常好的一个体现, 通过 HandlerAdapter, DispatcherServlet 就可以支持任何格式的Handler(这里的可以支持指在不改变 DispatcherServlet 的情况下), 第二是HandlerAdapter 基于不同Handler实现不同实现类(可以把它理解为策略模式), 最后也是最重要的就是参数的解析与返回值的解析(这个在下面进行叙述)!
8. 参考资料
SpringMVC源码分析系列
Spring MVC源码剖析
Spring源码情操陶冶
Spring 揭秘
Spring 技术内幕
Spring 源码深度分析
看透 Spring MVC 源代码分析与实践