源码基于SpringMVC 5.2.7版本
RequestMappingHandlerAdapter是SpringMVC核心组件之一,其负责请求的参数解析、调用请求具体处理方法、返回值处理。尤其参数解析、返回值处理这两项工作相当复杂。RequestMappingHandlerAdapter又分别交给参数解析器HandlerMethodArgumentResolver以及返回处理器HandlerMethodReturnValueHandler完成。RequestMappingHandlerAdapter执行完毕后将返回ModelAndView对象。ModelAndView包含了数据(model)和视图(view)。
request经过HandlerMapping找到了对应的Handler。但是要执行Handler,还需要从request中提取handler需要的参数,Handler执行后返回值也需要经过处理才能写入response返回给客户端。这些操作都是由MVC另一个核心组件-HandlerAdapter完成。
HandlerAdapter核心事情主要有3件:参数预处理、调用Handler、返回值处理。
- 参数预处理是从request的body、query、header等解析并转换为Handler对应的参数,这部分工作有一系列的参数解析器完成
- 调用Handler就是通过反射执行handler的方法体
- 返回值处理是对Handler的返回值进行处理,这部分工作由一组返回值处理器完成
HandlerAdapter初始化
首先了解一下DispatcherServlet如何确定请求对应的HandlerAdapter?DispatcherServlet本身的初始化的时候根据配置获取一组HandlerAdapter,依次遍历HandlerAdapter是否支持该请求对应的Handler。SpringMVC主要支持的HandlerAdapter类型有
HandlerAdapter类型 |
支持的Handler |
备注 |
---|---|---|
RequestMappingHandlerAdapter |
org.springframework.web.method.HandlerMethod |
RequestMappingHandlerMapping返回的Handler就是HandlerMethod |
HandlerFunctionAdapter |
org.springframework.web.servlet.function.HandlerFunction |
Spring5.2开始支持的一种Handler |
HttpRequestHandlerAdapter |
org.springframework.web.HttpRequestHandler |
|
SimpleControllerHandlerAdapter |
org.springframework.web.servlet.mvc.Controller |
|
SimpleServletHandlerAdapter |
javax.servlet.Servlet |
|
DispatcherServlet初始化HandlerAdapter逻辑与其初始化HandlerMapping逻辑类似,
- 如果"detectAllHandlerAdapters"打开,则从IOC容器中获取所有类型为HandlerAdapter的实例;否则进入2
- 从IOC容器中获取name为"handlerAdapter"的实例;
- 如果步骤1、2之后已经有HandlerAdapter则装配过程结束,否则进入4;
- 通过DispatcherServlet默认装配策略中创建HandlerAdapter实例,并装配给DispatcherServlet,装配过程结束。
默认情况“detectAllHandlerAdapters”是打开的,也就是说默认情况是从IOC容器中找到所有HandlerAdapter的Bean。DispatcherServlet默认装配策略在《抽丝剥茧MVC之RequestMappingHandlerMapping》中有介绍,这里就不赘述。
RequestMappingHandlerAdapter
在SpringMVC支持的几种HandlerAdapter中,最常用的就是RequestMappingHandlerAdapter。这种HandlerAdapter是配合@RequestMapping使用的。
RequestMappingHandlerAdapter主要成员
- argumentResolvers:org.springframework.web.method.support.HandlerMethodArgumentResolverComposite类型,参数解析器组合
- initBinderArgumentResolvers:org.springframework.web.method.support.HandlerMethodArgumentResolverComposite类型,DataBinder初始化方法(被@InitBinder注解)的参数解析器组合
- returnValueHandlers:org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite类型,返回值处理器组合
- requestResponseBodyAdvice:org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice和org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice类型的bean集合,在读request body或者写response body前后做一下特殊处理
- messageConverters:org.springframework.http.converter.HttpMessageConverter类型的对象集合,从request或者response读取或写入信息
RequestMappingHandlerAdapter的核心逻辑如下图所示
创建DataBinder工厂(WebDataBinderFactory)
DataBinder有两个作用:其一参数解析时做类型转换;其二参数解析时给对象设置属性(数据绑定)。这里只是创建DataBinder工厂,具体的DataBinder实例将在参数解析时根据需要由DataBinder工厂类创建。DataBinder工厂收集@InitBinder注解的方法,在创建DataBinder实例的时候依次执行这些方法达到初始化DataBinder的目的。@InitBinder可以用在2个地方。一个是@Controller注解的类中,一个是@ControllerAdvice注解的类中。收集@InitBinder就是从当前请求的Handler的类中找到@InitBinder注解的方法,以及所有@ControllerAdvice注解的类匹配当前请求的@InitBinder注解的方法。
DataBinder工厂执行@InitBinder方法时也涉及到参数解析,所以也需要注册参数解析器。如果开发者没有给@InitBinder配置相应的参数解析器,Spring将加载默认的@InitBinder参数解析器。
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
... ...
private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
return resolvers;
}
... ...
}
DataBinder工厂的实现类型创建DataBinder的源码如下:
public class DefaultDataBinderFactory implements WebDataBinderFactory {
... ...
public final WebDataBinder createBinder(
NativeWebRequest webRequest, @Nullable Object target, String objectName) throws Exception {
WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
if (this.initializer != null) {
this.initializer.initBinder(dataBinder, webRequest);
}
//笔者注:执行所有@InitBinder方法,初始化dataBinder
initBinder(dataBinder, webRequest);
return dataBinder;
}
... ...
}
初始化Model
创建Model工厂(ModelFactory)
与DataBinder工厂一样,Model工厂也会收集一些初始化Model的方法。两种方法将会被收集
1 请求Handler对应的@Controller类中被注解@ModelAttribute修饰且没有被注解@RequestMapping修饰的方法
2 @ControllerAdvice类被注解@ModelAttribute修饰且与请求Handler匹配的的方法
private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
Class<?> handlerType = handlerMethod.getBeanType();
Set<Method> methods = this.modelAttributeCache.get(handlerType);
if (methods == null) {
//笔者注:请求Handler中@ModuleAttribute注解且没有@RequestMapping注解的方法
methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
this.modelAttributeCache.put(handlerType, methods);
}
List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
// Global methods first
this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
//笔者注:@ControllerAdvice注解且匹配请求Handler类型的且有@ModuleAttribute的方法
if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
Object bean = controllerAdviceBean.resolveBean();
for (Method method : methodSet) {
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
}
});
for (Method method : methods) {
Object bean = handlerMethod.getBean();
attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
}
return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
初始化Model
初始化Model就是往Model中提前添加一些key-value。有3种情况
1 上一个请求通过FlashMap机制传递过来的参数,参考《FlashMap机制》
2 请求Handler关联的注解@SessionAttributes的session属性
3 Model工厂收集的@ModelAttribute方法,执行@ModelAttribute方法也需要参数解析,它的参数解析跟请求参数解析一致,解析器也是同一组解析器。
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
... ...
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
... ...
//笔者注:添加FalshMap机制传递的参数
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
//笔者注: 执行初始化逻辑
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
... ...
}
... ...
}
public final class ModelFactory {
... ...
public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod)
throws Exception {
//笔者注: @SessionAttributes注解的处理
Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
container.mergeAttributes(sessionAttributes);
//笔者注:执行Model工厂收集的@ModelAttribute方法
invokeModelAttributeMethods(request, container);
for (String name : findSessionAttributeArguments(handlerMethod)) {
if (!container.containsAttribute(name)) {
Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
if (value == null) {
throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
}
container.addAttribute(name, value);
}
}
}
... ...
}
请求解析参数
SpringMVC在执行请求的业务方法前解析request中的参数以匹配业务方法的形参。参数解析的工作由一个个的参数解析器完成。参数解析器org.springframework.web.method.support.HandlerMethodArgumentResolver接口的实现类。一般,系统在启动时注册多个参数解析器以解析不同的类型的参数。如果开发者没有配置解析器,那么SpringMVC将加载默认的解析器。加载的过程在RequestMappingHandlerAdapter的初始化过程中完成。源码如下:
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
... ...
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache();
//笔者注:如没有设置参数解析器,加载默认解析器
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//笔者注:如没有设置DataBinder的参数解析器,加载默认解析器。DataBinder的初始化方法也是反射,也需要参数解析。DataBinder的参数解析少很多
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//笔者注:如没有设置返回处理器,加载返回处理器
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
... ...
}
默认注册的参数解析器如下,各个参数解析器将在后面的章节中详细介绍。
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
... ...
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
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;
}
... ...
}
HandlerMethodArgumentResolverComposite负责从已注册的参数解析器中选择适合当前参数类型的解析器,并利用选取的解析器解析参数。选择的逻辑如下:
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
... ...
// 笔者注:选择第一个适合当前参数的解析器
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
... ...
}
请求返回值处理
请求的业务方法返回结果后,SpringMVC需要对结果进行处理。SpringMVC的返回值处理由返回处理器完成,返回处理器是org.springframework.web.method.support.HandlerMethodReturnValueHandler接口的实现类。一般,系统在启动时注册多个返回处理器以处理不同的类型的返回值。
同参数解析器一样,如果开发者没有主动配置返回处理器,那么SpringMVC将加载默认的返回处理器,该过程也是在RequestMappingHandlerAdapter初始化的时候完成。默认注册的返回处理器如下,各个返回类型处理器将在后面的章节中详细介绍。
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
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;
}
HandlerMethodReturnValueHandlerComposite负责从已注册的返回处理器中选择适合当前返回类型的处理器,并利用选取的处理器对返回值进行处理。选择的逻辑如下:
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
protected final Log logger = LogFactory.getLog(getClass());
private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
//笔者注:选择第一个支持的返回处理器
@Nullable
private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
... ...
}
返回ModelAndView
DispatcherServlet后面的流程视图渲染需要的是ModelAndView对象,所以需要将结果包装成ModelAndView对象。ModelAndView包含两个属性:model、view。model存储了请求执行后的数据,而view则是告诉DispatcherServlet用哪个视图解析器解析并渲染view返回到客户端。
在创建ModelAndView的时候有一点需要注意,如果model是org.springframework.web.servlet.mvc.support.RedirectAttributes类型,表明当前是重定向场景。此时,可能涉及到请求间的参数传递,需要将flashAttributes添加request的OUTPUT_FLASH_MAP属性中。详细情况参见《FlashMap机制-不同请求间传递参数》。
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
... ...
//笔者注:返回ModelAndView对象
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
//重定向场景需要将falshAttributes添加到request的属性中。参见FlashMap
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}
... ...
}
配置
RequestMappingHandlerAdapter配置形式与RequestMappingHandlerMapping一样。RequestMappingHandlerMapping支持的配置方式,RequestMappingHandlerAdapter也都支持。这里不在赘述。参考《RequestMappingHandlerMapping》
上一篇 RequestMappingHandlerMapping
下一篇 参数解析器HandlerMethodArgumentResolver
再下一篇 ModelAttribute使用方法