SpringMVC源码笔记3——HandlerAdapter的获取和执行
HandlerAdapter体系

HandlerAdapter接口
* supports(Object handler)
适配器模式的固定接口,表示是否支持对此Object handler进行适配调用
* ModelAndView handle
向外统一暴露的接口方法,其方法内的实现,不同的底层Object handler有不同的方法
* getLastModified
为了支持HTTP的缓存机制,进行服务器资源是否修改的判断,通常请求为get方法且会携带If-Modified-Since头
public interface HandlerAdapter {
boolean supports(Object var1);
ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
long getLastModified(HttpServletRequest var1, Object var2);
}
实现类
* 上一步获取的Handler处理器有多种,所以需要一个接口进行适配,主要的处理器适配器有:
RequestMappingHandlerAdapter:处理基于@RequstMapping注解的处理器
SimpleControllerHandlerAdapter:处理基于实现Controller接口或者Controller子类的处理器
HttpRequestHandlerAdapter:处理访问静态资源的请求
等等
SimpleControllerHandlerAdapter
* 例如BeanNameUrlHandlerMapping 支持使用容器bean的名称进行匹配
其中对应的处理器bean是需要实现Controller接口的
@FunctionalInterface
public interface Controller {
@Nullable
ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
public class myController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
mv.setViewName("KAKA");
return mv;
}
}
* SimpleControllerHandlerAdapter的实现
- supports基于实现Controller接口或者Controller子类的处理器
- handle底层就是直接调用((Controller) handler).handleRequest(request, response)
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof Controller);
}
@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}
HandlerFunctionAdapter
* 对RouterFunctionMapping中收集的基于RouterFunction类型的处理器
是轻量级函数式编程模型,其中函数用于路由和处理请求
@Bean
public RouterFunction<ServerResponse> student() {
return route()
.GET("/student/{id}", accept(MediaType.APPLICATION_JSON), request -> {
return ServerResponse.ok().body("name = " + request.param("name").get()) ;})
.build() ;
}
* HandlerFunctionAdapter
public class HandlerFunctionAdapter implements HandlerAdapter, Ordered {
private int order = Ordered.LOWEST_PRECEDENCE;
@Override
public boolean supports(Object handler) {
return handler instanceof HandlerFunction;
}
@Nullable
@Override
public ModelAndView handle(HttpServletRequest servletRequest,
HttpServletResponse servletResponse,
Object handler) throws Exception {
//把handler转为HandlerFunction后,调用其handle(serverRequest),在使用serverResponse.writeTo即可
HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;
ServerRequest serverRequest = getServerRequest(servletRequest);
ServerResponse serverResponse = handlerFunction.handle(serverRequest);
return serverResponse.writeTo(servletRequest, servletResponse,
new org.springframework.web.servlet.function.support.HandlerFunctionAdapter.ServerRequestContext(serverRequest));
}
...
}
RequestMappingHandlerAdapter实现类
概述

* AbstractHandlerMethodAdapter只是简单的增加了order的支持,其他核心方法都需要子类实现
子类需要实现supportsInternal(在RequestMappingHandlerAdapter直接返回true)和handleInternal方法
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
protected abstract boolean supportsInternal(HandlerMethod handlerMethod);
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
@Nullable
protected abstract ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
...
}
主要成员变量
// ======================相关成员变量们======================
// 装载RequestBodyAdvice和ResponseBodyAdvice的实现类们~
private List<Object> requestResponseBodyAdvice = new ArrayList<>();
// @ModelAttribute注解相关
// 这里意思是:含有@ModelAttribute,但是但是但是不含有@RequestMapping注解的方法~~~~~
public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method -> (!AnnotatedElementUtils.hasAnnotation(method, RequestMapping.class) && AnnotatedElementUtils.hasAnnotation(method, ModelAttribute.class));
// 存储标注了@ModelAttribute注解的方法的缓存~~~~
private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<>();
//@InitBinder注解相关
// 标注了注解@InitBinder的方法~~~
public static final MethodFilter INIT_BINDER_METHODS = method -> AnnotatedElementUtils.hasAnnotation(method, InitBinder.class);
// 存储标注了@InitBinder注解的方法的缓存~~~~
private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<>();
//参数相关解析器
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
private HandlerMethodArgumentResolverComposite argumentResolvers;
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
//返回值相关解析器
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
//ModelAndView解析器
private List<ModelAndViewResolver> modelAndViewResolvers;
//mediaTypes、消息转换支持器
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
private List<HttpMessageConverter<?>> messageConverters;
//其他
private WebBindingInitializer webBindingInitializer;
private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");
private Long asyncRequestTimeout;
private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0];
private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0];
private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
private boolean ignoreDefaultModelOnRedirect = false;
private int cacheSecondsForSessionAttributeHandlers = 0;
private boolean synchronizeOnSession = false;
private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
private ConfigurableBeanFactory beanFactory;
private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64);
afterPropertiesSet收集@ControllerAdvice和参数/结果解析器
实现了InitializingBean的afterPropertiesSet()方法,
* 从容器中获取添加@ControllerAdvice注解的实例使用ControllerAdviceBean封装起来,且排序,进行遍历每一个ControllerAdviceBean控制器增强对象
- 找到添加了@ModelAttributed但没有@RequestMapping的方法加入到Map<ControllerAdviceBean,Set<Method>> modelAttributeAdviceCache
- 找到添加@InitBinder的方法,加入到Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache
- 如果此实例实现了ResponseBodyAdvice/RequestBodyAdvice接口的对象,会加入List<Object> requestResponseBodyAdvice
* 创建默认的参数解析器组合(存在上下顺序)
- 基于注解的参数,例如@RequestParam、、@PathVariable、@ModelAttribute、@RequestBody等
- 基于类型的参数,ServletRequest、HttpSession、InputStream、ServletResponse、HttpEntity、Model等
- 用户定义的类型
- 设置最后兜底(可处理所有类型)
* 创建默认的Binder绑定参数解析器组合,它默认支持的比参数解析器少一些
支持@RequestParam、@PathVariable、@PathVariable等,不支持@RequestBody、@ModelAttributed、@RequestPart等
* 创建默认的结果解析器组合
- 基于返回类型的处理,如ModelAndView、HttpEntity、DeferredResult等
- 基于注解,如标注了@ModelAttribute、@esponseBody
- Map、CharSequence或者void的返回类型
- 自定义
public void afterPropertiesSet() {
this.initControllerAdviceCache();
List handlers;
if (this.argumentResolvers == null) {
handlers = this.getDefaultArgumentResolvers();
this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
}
if (this.initBinderArgumentResolvers == null) {
handlers = this.getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
}
if (this.returnValueHandlers == null) {
handlers = this.getDefaultReturnValueHandlers();
this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
}
}
public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) {
List<ControllerAdviceBean> adviceBeans = new ArrayList<>();
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, Object.class)) {
if (!ScopedProxyUtils.isScopedTarget(name)) {
ControllerAdvice controllerAdvice = context.findAnnotationOnBean(name, ControllerAdvice.class);
if (controllerAdvice != null) {
// Use the @ControllerAdvice annotation found by findAnnotationOnBean()
// in order to avoid a subsequent lookup of the same annotation.
adviceBeans.add(new ControllerAdviceBean(name, context, controllerAdvice));
}
}
}
OrderComparator.sort(adviceBeans);
return adviceBeans;
}
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
//基于注解的参数,例如@RequestParam、@RequestBody、@PathVariable等
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());
//基于类型的参数,ServletRequest、HttpSession、InputStream、ServletResponse、HttpEntity、Model等
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());
// 用户定义的类型
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
//设置默认
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
//同上,只不过少了一些
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;
}
//
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
// 基于返回类型的处理,如ModelAndView、HttpEntity等
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));
//基于注解,如标注了@ModelAttribute、@esponseBody
handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
//Map、CharSequence或者void的返回类型
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
//自定义
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;
}
handleInternal方法主流程
实现了handleInternal方法,其内调用invokeHandleMethod以处理核心逻辑
HandlerAdapter.handle -> AbstractHandlerMethodAdapter.handleInternal(略) -> RequestMappingHandlerAdapter->invokeHandleMethod
具体解析见下节:执行HandlerAdapter.handle(以RequestMappingHandlerAdapter为例)
* 把原生request和response封装为ServletWebRequest ,主要提供一些属性处理方法,如果getSession
* 获取数据绑定工厂WebDataBinderFactory ,会收集所有@initBinder方法作为绑定对象,在后续进行类型转换的时候可能会用到
* 把最初的handlerMethod封装为ServletInvocableHandlerMethod,增加了参数解析和返回结果处理的功能
* 数据模型ModelAndView的处理,包括数据模型处理工厂ModelFactory 和ModelAndViewContainer 的创建和设置
* 异步请求的处理
* 调用ServletInvocableHandlerMethod.invokeAndHandle,先进行参数解析,再对结果进行处理
private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//再次封装了Tomcat的HttpServletRequest和HttpServletResponse,主要提供属性处理,集中了request和sessiond的
ServletWebRequest webRequest = new ServletWebRequest(request, response);
//数据绑定工厂,会收集所有@initBinder方法作为绑定对象,
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
//数据模型处理工厂
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
//把最初的handlerMethod封装为ServletInvocableHandlerMethod,增加了参数解析和返回结果处理的功能
ServletInvocableHandlerMethod requestMappingMethod = this.createRequestMappingMethod(handlerMethod, binderFactory);
//ModelAndView模块的处理
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
//异步请求的处理
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
}
//调用ServletInvocableHandlerMethod,先进行参数解析,再对结果进行处理
requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
//进行ModelAndView处理
return asyncManager.isConcurrentHandlingStarted() ? null : this.getModelAndView(mavContainer, modelFactory, webRequest);
}
执行拦截器链的前置方法
使用HandlerExecutionChain的applyPreHandle方法
* 获取当前HandlerExecutionChain处理器执行链的配置的拦截器集合
* 遍历每一个拦截器的applyPreHandle,当有一个失败时返回false中断处理,
在调用triggerAfterCompletion,会逆序调用每一个拦截器的afterCompletion清理作用
@Nullable
public HandlerInterceptor[] getInterceptors() {
if (this.interceptors == null && this.interceptorList != null) {
this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);
}
return this.interceptors;
}
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {
HandlerInterceptor interceptor = getInterceptors()[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.afterCompletion(request, response, this.handler, ex);
}
}
执行HandlerAdapter.handle(以RequestMappingHandlerAdapter为例)

概述
实现了handleInternal方法,其内调用invokeHandleMethod以处理核心逻辑
HandlerAdapter.handle -> AbstractHandlerMethodAdapter.handleInternal(略) -> RequestMappingHandlerAdapter->invokeHandleMethod
* 把原生request和response封装为ServletWebRequest ,主要提供一些属性处理方法,如果getSession
* 获取数据绑定工厂WebDataBinderFactory ,会收集所有@initBinder方法作为绑定对象,在后续进行类型转换的时候可能会用到
* 把最初的handlerMethod封装为ServletInvocableHandlerMethod,增加了参数解析和返回结果处理的功能
* 数据模型ModelAndView的处理,包括数据模型处理工厂ModelFactory 和ModelAndViewContainer 的创建和设置
* 异步请求的处理
* 调用ServletInvocableHandlerMethod.invokeAndHandle,先进行参数解析,再对结果进行处理
private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//再次封装了Tomcat的HttpServletRequest和HttpServletResponse,主要提供属性处理,集中了request和sessiond的
ServletWebRequest webRequest = new ServletWebRequest(request, response);
//数据绑定工厂,会收集所有@initBinder方法作为绑定对象,
WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
//数据模型处理工厂
ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
//把最初的handlerMethod封装为ServletInvocableHandlerMethod,增加了参数解析和返回结果处理的功能
ServletInvocableHandlerMethod requestMappingMethod = this.createRequestMappingMethod(handlerMethod, binderFactory);
//ModelAndView模块的处理
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
//异步请求的处理
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
}
//调用ServletInvocableHandlerMethod,先进行参数解析,再对结果进行处理
requestMappingMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
//进行ModelAndView处理
return asyncManager.isConcurrentHandlingStarted() ? null : this.getModelAndView(mavContainer, modelFactory, webRequest);
}
获取WebDataBinderFactory数据绑定工厂
创建工厂流程
* 在RequestMappingHandlerAdapter.invokeHandleMethod中调用getDataBinderFactory经获取WebDataBinderFactory,
会先遍历@ControllerAdvice类中的,和本@Controller类中的方法@InitBinder注解的所有方法。封装为InvocableHandlerMethod缓存起来
* 在把上一步的方法集合作为参数创建数据绑定工厂createDataBinderFactory(initBinderMethods);
把@InitBinder注解的方法和类封装为InvocableHandlerMethod即可,因为只需要进行方法的参数解析
在使用WebDataBinder.convertIfNecessary进行转换获取(这一步骤详情见上几节),这里就会优先用到上一步注册的自定义转换器,进行类型转换
private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
//当前控制器类对象,即添加了@Controller注解的类对象,获取其中添加了@InitBinder注解的所有方法
Class<?> handlerType = handlerMethod.getBeanType();
Set<Method> methods = (Set)this.initBinderCache.get(handlerType);
if (methods == null) {
methods = HandlerMethodSelector.selectMethods(handlerType, INIT_BINDER_METHODS);
this.initBinderCache.put(handlerType, methods);
}
//RequestMappingHandlerAdapter中afterPropertiesSet初始化的所有添加@ControllerAdvice类中添加@InitBinder注解的所有方法
List<InvocableHandlerMethod> initBinderMethods = new ArrayList();
Iterator var5 = this.initBinderAdviceCache.entrySet().iterator();
//代码略,先遍历@ControllerAdvice类中的,在@Controller类中的方法@InitBinder注解的所有方法。封装为InvocableHandlerMethod缓存起来
initBinderMethods.add(this.createInitBinderMethod(bean, method));
return this.createDataBinderFactory(initBinderMethods);
}
//把@InitBinder注解的方法和类封装为InvocableHandlerMethod即可,因为只需要进行方法的参数解析
private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
if (this.initBinderArgumentResolvers != null) {
binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
}
binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
return binderMethod;
}
//最终创建的ServletRequestDataBinderFactory,会把RequestMappingHandlerAdapter里用户设置的WebBindingInitializer传递过去
//WebBindingInitializer默认为ConfigurableWebBindingInitializer,是用于自定义配置最终使用的WebDataBinder绑定器
protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods) throws Exception {
return new ServletRequestDataBinderFactory(binderMethods, this.getWebBindingInitializer());
}
@InitBinder使用实例
最终转为添加自定义的PropertyEditor
(1)举例使用
public class StringToListPropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
String[] resultArr = null;
if (!StringUtils.isEmpty(text)) {
resultArr = text.split("_");
}
setValue(resultArr);
}
}
@RequestMapping("/myStringToList")
@Controller
public class StringToListController {
@InitBinder
public void myStringToListBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(String[].class, new StringToListPropertyEditor());
}
//请求strToListArr = 1_2_3
@RequestMapping(value = "/test", method = RequestMethod.GET)
@ResponseBody
public String myStringToListTest(String[] strToListArr, HttpServletResponse response) {
return Arrays.asList(strToListArr).toString();//返回数组{1,2,3}
}
}
工厂使用的时机
一般在参数解析解析的节点,在获取到指定参数对应原始值后,必要的时候会用到数据绑定工厂进行类型转换,如下@RequestParam解析棋类继承抽象解析类:
* 先使用工厂创建一个WebDataBinder对象(见其他章节),并对其进行初始化,收集所有符合@InitBinder注解方法,执行方法体。
其最终目的就是为传递进去的dataBinder设置自定义的转换器
@InitBinder
public void myStringToListBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(String[].class, new StringToListPropertyEditor());
}
* 在使用WebDataBinder.convertIfNecessary进行转换获取(这一步骤详情见上几节),这里就会优先用到上一步注册的自定义转换器,进行类型转换
WebDataBinder最终使用委托类TypeConverterDelegate,TypeConverterDelegate在处理最终转换的时候,
会用到PropertyEditorRegistrySupport 收集的默认和用户自定义的Editor和Conversion
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
//略
@Override
public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Class<?> paramType = parameter.getParameterType();
NamedValueInfo namedValueInfo = getNamedValueInfo(parameter);
Object arg = resolveName(namedValueInfo.name, parameter, webRequest);
//略
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name);
arg = binder.convertIfNecessary(arg, paramType, parameter);
}
handleResolvedValue(arg, namedValueInfo.name, parameter, mavContainer, webRequest);
return arg;
}
}
public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
throws Exception {
WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
//执初始化器,比如为dataBinder设置自定义的ConversionService
if (this.initializer != null) {
this.initializer.initBinder(dataBinder, webRequest);
}
//找到对应的@InitBinder注解方法,解析参数,最终执行方法
initBinder(dataBinder, webRequest);
return dataBinder;
}
public void initBinder(WebDataBinder binder, NativeWebRequest request) throws Exception {
for (InvocableHandlerMethod binderMethod : this.binderMethods) {
//如果注解内有指定name就需要进校验,没有就为共用的
if (isBinderMethodApplicable(binderMethod, binder)) {
//这个和解析控制器@RquestMapping方法一样,目的就是为了执行方法
Object returnValue = binderMethod.invokeForRequest(request, null, binder);
if (returnValue != null) {
throw new IllegalStateException("@InitBinder methods should return void: " + binderMethod);
}
}
}
}
获取ModelFactory数据模型处理工厂
* 先获取类上@SessionAttribute注解的信息,取name和type,封装到SessionAttributesHandler
* 再获取本类上添加了@ModelAttribute且没有@RequestMapping的方法
这些方法标可以用于把方法结果作为一个或多个属性添加到Model上
* 再获取modelAttributeAdviceCache事先收集的全局controllerAdviceBean中实例
- 调用其controllerAdviceBean.isApplicableToBeanType(handlerType),一般为相同包路径,相同类型、相同注解即可匹配
- 类匹配的话,即可收集controllerAdviceBean上添加了@ModelAttribute且没有@RequestMapping的方法
* 在把上一步的方法集合作为参数创建数据绑定工厂createModelAttributeMethod
把@ModelAttribut注解的方法和类封装为InvocableHandlerMethod即可,因为只需要进行方法的参数解析
* 组合创建ModelFactory(attrMethods, binderFactory, sessionAttrHandler)返回接口
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) {
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) -> {
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);
}
private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) {
InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
if (this.argumentResolvers != null) {
attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
attrMethod.setDataBinderFactory(factory);
return attrMethod;
}
把HandlerMethod封装为ServletInvocableHandlerMethod
* ServletInvocableHandlerMethod 增加了参数解析和返回结果处理的功能
所以ServletInvocableHandlerMethod需要设置参数解析器、返回结果解析器、以及参数名称发现器
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
private ServletInvocableHandlerMethod createRequestMappingMethod(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
ServletInvocableHandlerMethod requestMethod = new ServletInvocableHandlerMethod(handlerMethod);
//需要4个关联组件
requestMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
requestMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
requestMethod.setDataBinderFactory(binderFactory);
requestMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
return requestMethod;
}
* 三者关系

* HandlerMethod
- 在HandlerMappings初始化的时候就会对指定的控制器方法封装为HandlerMethod对象,主要封装了如下信息
private final Object bean; //控制器类对象
private final BeanFactory beanFactory;
private final Method method; //控制器方法
private final Method bridgedMethod;
private final MethodParameter[] parameters; //控制器方法参数
@RequestMapping(value = "/list", headers = "",consumes = "")
@ResponseBody
public List<User> list() {
//..
return List<User> users = userService.list();;
}
* InvocableHandlerMethod
- 封装了参数解析器组合的处理
- 提供invokeForRequest方法,借助HandlerMethodArgumentResolver集合和DataBinderFactory数据转换工厂
先进行一个个的参数解析,获取最终的参数列表,才反射调用方法
* ServletInvocableHandlerMethod
- 封装了结果解析器组合的处理
- 提供invokeAndHandle方法,,借助HandlerMethodReturnValueHandlers集合和DataBinderFactory数据转换工厂对结果解析
创建ModelAndViewContainer并初始化
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
ModelAndViewContainer介绍
* ModelAndViewContainer可以把它定义为ModelAndView上下文的容器,它承担着整个请求过程中的数据传递工作–>保存着Model和View
- 它维护了模型model:包括defaultModle和redirectModel
defaultModel是默认使用的Model,redirectModel是用于传递redirect时的Model
- 在Controller处理器入参写了Model或ModelMap类型时候,实际传入的是defaultModel。
defaultModel它实际是BindingAwareModel,底层就是个Map。而且继承了ModelMap又实现了Model接口,所以在处理器中使用Model或ModelMap时,其实都是使用同一个对象~~~
可参考MapMethodProcessor,它最终调用的都是mavContainer.getModel()方法
- 若处理器入参类型是RedirectAttributes类型,最终传入的是redirectModel。
- 维护视图view(兼容支持逻辑视图名称)
- 维护是否redirect信息,及根据这个判断HandlerAdapter使用的是defaultModel或redirectModel
- 维护@SessionAttributes注解信息状态
- 维护handler是否处理标记(重要)
例如在最后的getModelAndView方法会判断此属性,如果ModelAndViewContainer已经被处理过,此处直接返回null,也就是不会再继续处理Model和View了~
public class ModelAndViewContainer {
// =================它所持有的这些属性还是蛮重要的=================
// redirect时,是否忽略defaultModel 默认值是false:不忽略
private boolean ignoreDefaultModelOnRedirect = false;
// 此视图可能是个View,也可能只是个逻辑视图String
@Nullable
private Object view;
// defaultModel默认的Model
// 注意:ModelMap 只是个Map而已,但是实现类BindingAwareModelMap它却实现了org.springframework.ui.Model接口
private final ModelMap defaultModel = new BindingAwareModelMap();
// 重定向时使用的模型(提供set方法设置进来)
@Nullable
private ModelMap redirectModel;
// 控制器是否返回重定向指令
// 如:使用了前缀"redirect:xxx.jsp"这种,这个值就是true。然后最终是个RedirectView
private boolean redirectModelScenario = false;
// Http状态码
@Nullable
private HttpStatus status;
private final Set<String> noBinding = new HashSet<>(4);
private final Set<String> bindingDisabled = new HashSet<>(4);
// 很容易想到,它和@SessionAttributes标记的元素有关
private final SessionStatus sessionStatus = new SimpleSessionStatus();
// 这个属性老重要了:标记handler是否**已经完成**请求处理
// 在链式操作中,这个标记很重要
private boolean requestHandled = false;
...
public void setViewName(@Nullable String viewName) {
this.view = viewName;
}
public void setView(@Nullable Object view) {
this.view = view;
}
// 是否是视图的引用
public boolean isViewReference() {
return (this.view instanceof String);
}
// 是否使用默认的Model
private boolean useDefaultModel() {
return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));
}
// 注意子方法和下面getDefaultModel()方法的区别
public ModelMap getModel() {
if (useDefaultModel()) { // 使用默认视图
return this.defaultModel;
} else {
if (this.redirectModel == null) { // 若重定向视图为null,就new一个空的返回
this.redirectModel = new ModelMap();
}
return this.redirectModel;
}
}
// @since 4.1.4
public ModelMap getDefaultModel() {
return this.defaultModel;
}
// @since 4.3 可以设置响应码,最终和ModelAndView一起被View渲染时候使用
public void setStatus(@Nullable HttpStatus status) {
this.status = status;
}
// 以编程方式注册一个**不应**发生数据绑定的属性,对于随后声明的@ModelAttribute也是不能绑定的
// 虽然方法是set 但内部是add哦 ~~~~
public void setBindingDisabled(String attributeName) {
this.bindingDisabled.add(attributeName);
}
public boolean isBindingDisabled(String name) {
return (this.bindingDisabled.contains(name) || this.noBinding.contains(name));
}
// 注册是否应为相应的模型属性进行数据绑定
public void setBinding(String attributeName, boolean enabled) {
if (!enabled) {
this.noBinding.add(attributeName);
} else {
this.noBinding.remove(attributeName);
}
}
// 这个方法需要重点说一下:请求是否已在处理程序中完全处理
// 举个例子:比如@ResponseBody标注的方法返回值,无需View继续去处理,所以就可以设置此值为true了
// 说明:这个属性也就是可通过源生的ServletResponse、OutputStream来达到同样效果的
public void setRequestHandled(boolean requestHandled) {
this.requestHandled = requestHandled;
}
public boolean isRequestHandled() {
return this.requestHandled;
}
// =========下面是Model的相关方法了==========
// addAttribute/addAllAttributes/mergeAttributes/removeAttributes/containsAttribute
}
initModel方法为Model初始化属性
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
会获取到当前方法,所需要的属性值,在保存到mavContainer上下文中
①获取SessionAttributesHandler里名先获取类上明确指定的@SessionAttribute的信息,即name和type,这里的数据以及封装在modelFactory了
再从request对象里获取会话中对应的属性值,加入到ModelAndViewContainer的model中,底层执行request.getAttribute(name, WebRequest.SCOPE_SESSION);
②执行工厂收集到的@ModelAttribute方法
把注解上的name属性作为name,为空默认为返回类型的泛型+类型名,
方法返回值作为vaule
设置到ModelAndViewContainer中
③遍历处理器handlerMethod上的标注ModelAttribute注解的参数,如果在①中获得的不存在,那么尝试从从request对象里获取会话中对应的属性值,
不存在报错,存在再加入到ModelAndViewContainer中
public void initModel(NativeWebRequest request, ModelAndViewContainer container, HandlerMethod handlerMethod)
throws Exception {
//获取SessionAttributesHandler里名先获取类上@SessionAttribute的信息,即name和type
//从request对象里获取会话中对应的属性值,加入到ModelAndViewContainer中
//request.getAttribute(name, WebRequest.SCOPE_SESSION);
Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
container.mergeAttributes(sessionAttributes);
//执行工厂收集到的@ModelAttribute方法
//注解上的name属性作为name,为空默认为返回类型的泛型+类型名,方法放入返回值作为vaule
invokeModelAttributeMethods(request, container);
//遍历处理器handlerMethod上的标注ModelAttribute注解且同时是@SessionAttributesHandler里面指定存在的会话属性
//作为从request对象里获取会话中对应的属性值,加入到ModelAndViewContainer中
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);
}
}
}
public Map<String, Object> retrieveAttributes(WebRequest request) {
Map<String, Object> attributes = new HashMap<>();
//knownAttributeNames即为收集到的类上@SessionAttributes信息
for (String name : this.knownAttributeNames) {
Object value = this.sessionAttributeStore.retrieveAttribute(request, name);
if (value != null) {
attributes.put(name, value);
}
}
return attributes;
}
@Override
@Nullable
public Object retrieveAttribute(WebRequest request, String attributeName) {
//getAttributeNameInSession默认返回attributeName
String storeAttributeName = getAttributeNameInSession(request, attributeName);
//从底层的请求对象中获取
return request.getAttribute(storeAttributeName, WebRequest.SCOPE_SESSION);
}
private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container)
throws Exception {
while (!this.modelMethods.isEmpty()) {
InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
if (container.containsAttribute(ann.name())) {
if (!ann.binding()) {
container.setBindingDisabled(ann.name());
}
continue;
}
Object returnValue = modelMethod.invokeForRequest(request, container);
if (!modelMethod.isVoid()){
String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
if (!ann.binding()) {
container.setBindingDisabled(returnValueName);
}
if (!container.containsAttribute(returnValueName)) {
container.addAttribute(returnValueName, returnValue);
}
}
}
}
private List<String> findSessionAttributeArguments(HandlerMethod handlerMethod) {
List<String> result = new ArrayList<>();
for (MethodParameter parameter : handlerMethod.getMethodParameters()) {
if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
String name = getNameForParameter(parameter);
Class<?> paramType = parameter.getParameterType();
if (this.sessionAttributesHandler.isHandlerSessionAttribute(name, paramType)) {
result.add(name);
}
}
}
return result;
}
异步请求WebAsyncManager的处理(略)
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
执行InvocableMethod.invokeAndHandle方法
整体流程
* 调用invokeForRequest(webRequest, mavContainer)获取处理的返回值,此时不带providedArgs
- 会先进行参数解析,对参数进行赋值
- 反射执行处理器内容,返回结果
* 判断处理器是否结束
如果结束,就直接return,而不必走后续的流程
* 调用handleReturnValue,处理返回值,返回处理后的结果
//RequestMappingHandlerAdapter
invocableMethod.invokeAndHandle(webRequest, mavContainer);
//ServletInvocableHandlerMethod类
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//解析参数、执行处理器方法,返回结果
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
//结果处理(见下节)
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {throw ex;}
}
参数解析
主要流程
* 从对应的HandlerMethod处理器方法对象获取对应的参数信息数组MethodParameter[] parameters,这里封装了每一个参数的注解、参数类型等信息。
使用Spring自带的MethodParameter来获取方法参数信息(有缓存处理),会使用一些native方法、字节码解析等获取方法信息,而不是反射
* 遍历每一个MethodParameter参数对象,设置下参数名称、参数类型的辅助解析对象
* 如果方法参数的类型,在providedArgs中存在,那直接获取(这里是处理@Initbandler时会用到),而无需在参数解析器处理
* 在参数解析器组合找到第一个合适的,调用其resolveArgument方法进行解析,返回结果
* 解析后的参数数组作为参数,对方法进行反射调用获取返回值
//InvocableHandlerMethod类
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {
//参数解析核心方法
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
//反射调用
Object returnValue = doInvoke(args);
return returnValue;
}
//参数解析核心方法
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//从底层HandlerMethod获取控制器方法的参数列表
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
//设置参数名称发现对象
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
//设置参数对象的参数类型
GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
//是否提前返回providedArgs
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
//在参数解析器组合找到第一个合适的,进行解析即可
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
throw ex;
}
}
if (args[i] == null) {throw new IllegalStateException(msg);
}
}
return args;
}
默认的参数解析器列表(顺序由上往下)
(1)基于注解的参数
* RequestParamMethodArgumentResolver(getBeanFactory(), false));
- 支持条件:@RequestParam(value="sum",defaultValue="10" , required=false) int sum
类型MultipartFile/Part、内嵌/集合类型为MultipartFile/Part
- 取值处理:name优先取@RequestParam注解的,否则取参数名称
从multipartRequest.getFile(name)、r equest.getParameterValues(name)(url + 表单参数值)
使用WebDataBinder进行必要的类型转换(不必对对象内部属性转换)
* RequestParamMapMethodArgumentResolver());
- 支持条件:@RequestParam Map<String,String> map
- 取值逻辑同上
* PathVariableMethodArgumentResolver());
- 支持条件:@PathVariable("username") String username
- 取值处理:在RequestMappingInfoHandlerMapping里的handleMatch的方法里,即位于把请求匹配到一个处理器的过程中
就以及通过getUrlPathHelper()对路径解析好存于请求request的属性中,在这里已经取值即可
使用WebDataBinder进行必要的类型转换
* PathVariableMapMethodArgumentResolver());
- 支持条件:@PathVariableMap注解
- 取值逻辑同上
* MatrixVariableMethodArgumentResolver());
- 支持条件:@MatriVariable(pathVar="hotelId "value="floor") int floor ; //http://localhost:8080/hotel/43;floor=7;room=15/guest
- 取值处理:在RequestMappingInfoHandlerMapping里的handleMatch的方法里,即位于把请求匹配到一个处理器的过程中
就以及通过getUrlPathHelper().decodePathVariables(request, uriVariables)解析好存于请求request的属性中,在这里已经取值即可
使用WebDataBinder进行必要的类型转换
* MatrixVariableMapMethodArgumentResolver());
- 支持条件:@MatrixVariableMap注解
- 取值逻辑同上
* ServletModelAttributeMethodProcessor(false));
- 支持条件:存在@ModelAttribute注解
- 取值处理: ①name优先取@ModelAttribute注解的,否则取参数名称,作为Model里对应的key
②设置@ModelAttribute中binding属性,解决Model里是否可用
③如果在Model里存在name的值,直接取返回
④如果没有,走创建流程:
从路径参数、request中获取name对应的值,再转换为对应类型,如果成功就返回
如果没有,就在尝试使用参数类型的构造方法(存在构造参数从request.getParameterNames()参数中获取)创建实例
⑤对创建成功的实例,使用equest.getParameterNames()进行实例内属性数据类型转换、Model里更新
⑥如果创建失败,则必要返回BindingResult或抛出异常
* RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
- 支持条件:@RequestBody
- 取值处理:见下
* RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
- 支持条件:@RequestPart("name"),注:它和@RequestParam是互斥的
- 取值逻辑:略
* RequestHeaderMethodArgumentResolver(getBeanFactory()));
- 支持条件:@RequestBody
- 取值处理:request.getHeaderValues
* RequestHeaderMapMethodArgumentResolver());
- 支持条件:@RequestHeaderMap
- 取值处理:见下
* ServletCookieValueMethodArgumentResolver(getBeanFactory())); //@CookieValue
- 支持条件:@CookieValue
- 取值处理:request.getCookies()
* ExpressionValueMethodArgumentResolver(getBeanFactory()));
- 支持条件:@Value
- 取值处理:${}占位符解析配置文件的值和解析Spring EL 表达式,获取最终的结果)
* SessionAttributeMethodArgumentResolver());
- 支持条件:@SessionAttribute
- 取值处理:name优先取@SessionAttribute注解的,否则取参数名称
request.getAttribute(name, RequestAttributes.SCOPE_SESSION)
* RequestAttributeMethodArgumentResolver());
- 支持条件:@RequestAttribute
- 取值处理:name优先取@RequestAttribute注解的,否则取参数名称
request.getAttribute(name, RequestAttributes.SCOPE_REQUEST)
(2)基于类型的参数
* ServletRequestMethodArgumentResolver());
- 支持条件:WebRequest/ServletRequest/MultipartRequest/HttpSession/Principal/InputStream/Reader/HttpMethod/Locale等
- 取值处理:取值均是从当前的请求request对象中获取到的
* ServletResponseMethodArgumentResolver());
- 支持条件:ServletResponse/OutputStream/Writer
- 取值处理:取值均是从当前的请求request对象中获取到的,如response.getOutputStream(); response.getWriter();
* HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice)); //HttpEntity/RequestEntity
- 支持条件:HttpEntity<T>
- 取值处理:获取泛型T的类型,使用AbstractMessageConverterMethodArgumentResolver的readWithMessageConverters方法的进行基于Contenty-type和accept
的消息流读取和转换获取到最终的格式化后的body,在返回new HttpEntity<>(body, inputMessage.getHeaders());
* RedirectAttributesMethodArgumentResolver());
- 支持条件:RedirectAttributes
- 取值处理:创建ModelMap redirectAttributes= new RedirectAttributesModelMap(dataBinder);,再mavContainer.setRedirectModel(redirectAttributes);后
直接返回redirectAttributes
* ModelMethodProcessor());
- 支持条件:Model
- 取值处理:直接返回mavContainer.getModel()
* MapMethodProcessor());
- 支持条件:无注解Map
- 取值处理:直接返回mavContainer.getModel()
* ErrorsMethodArgumentResolver());
- 支持条件:Errors
- 取值处理:判断mavContainer.getModel()里最后一个对象是否为BindingResult,是的返回,否则抛出异常
* SessionStatusMethodArgumentResolver());
- 支持条件:SessionStatus
- 取值处理:直接返回mavContainer.getSessionStatus()
* UriComponentsBuilderMethodArgumentResolver());
- 支持条件:UriComponentsBuilder
- 取值处理:返回基于当前request构建的ServletUriComponentsBuilder
(3)用户定义的类型
resolvers.addAll(getCustomArgumentResolvers());
(4)设置最后兜底(可处理所有类型)
* RequestParamMethodArgumentResolver(getBeanFactory(), true)); //
- 支持条件:(非Void下的基本类型) /Enum/CharSequence/Number/Date/Temporal/URI./URL/Locale/Class
- 取值处理:同上RequestParamMethodArgumentResolver(getBeanFactory(), false));
* ServletModelAttributeMethodProcessor(true));
- 支持条件:上面RequestParamMethodArgumentResolver(getBeanFactory(), true))需要的类型除外,无需存在@ModelAttribute注解
- 取值处理:同上ServletModelAttributeMethodProcessor(false));
RequestResponseBodyMethodProcessor解析@RequestBody
对应的解析器为RequestResponseBodyMethodProcessor

参数解析接口
public interface HandlerMethodArgumentResolver {
//支持解析的类型
boolean supportsParameter(MethodParameter parameter);
//进行解析
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}
(1)AbstractMessageConverterMethodArgumentResolver
此抽象类实现了HandlerMethodArgumentResolver但是没有实现接口方法,交于子类实现RequestResponseBodyMethodProcessor,
但子类最终会回调readWithMessageConverters进行数据转换
此抽象类主要提供了:
* 在构造器参数中传入了收集了解析器、requestResponseBodyAdvice
①接收各种http的报文解析器List<HttpMessageConverter<?>>messageConverters messageConverters
获取这些报文解析器支持的类型MediaTypes,并进行排序,q大的会排在前面,q一样,参数多的排在前面
如,audio/*;q=0.7 > audio/*;q=0.3
audio/basic;level=1 > audio/basic
②接收了requestResponseBodyAdvice类型集合,和封装到RequestResponseBodyAdviceChain
public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> converters,
@Nullable List<Object> requestResponseBodyAdvice) {
this.messageConverters = converters;
this.allSupportedMediaTypes = getAllSupportedMediaTypes(converters);
this.advice = new RequestResponseBodyAdviceChain(requestResponseBodyAdvice);
}
* 核心方法readWithMessageConverters实现
①把Tomcat的原生网络输入流HttpServletRequest封装为ServletServerHttpRequest(servletRequest) inputMessage
- HttpHeaders getHeaders()处理ContentType、ContentLength请求头
先收集Headers集合:从底层HttpServletRequest.getHeaderNames()获取所有请求头键值对,如果其中ContentType为空,使用HttpServletRequest.getContentType()获取
如果获取到的ContentType的Charset为空,则使用HttpServletRequest.getCharacterEncoding
- 实现InputStream getBody()方法
如果请求是表单:调用request.getParameterMap()获取原始HttpServletRequest以及解析好的参数表,使用k=v&k2=v2形式拼接为字符串,再转为ByteArrayInputStream
如果请求不是:直接返回HttpServletRequest.getInputStream().
需要主要的是,表单的处理会进行读取输入流,获取url和请求体中的所有参数封装到InputStream,这里就把原生的请求输入流读取了,流数据将清空,
无法再次读取,如果后续需要用到,应当在调用此方法之后使用一个变量保存起来
②从请求头获取contentType,如果为空,默认为application/octet-stream
③contextClass为null;argetClass为参数的实际类型,例如List<A>,则为A
④对入参HttpInputMessage inputMessage进行简单封装,保存了headers和body InputStream引用
⑤遍历收集到的报文解析器
- 如果converter是GenericHttpMessageConverter类型,则使用canRead(targetType, contextClass, contentType)判断
否则使用canRead(targetClass, contentType))判断
- 可以转换时
如果存在请求body,则前置Advice().beforeBodyRead方法-> converter.read方法->getAdvice().afterBodyRead方法
否则,执行advice.handleEmptyBody方法
⑥最终解析的body为空对象时,不为空就直接返回了
- 如果本次请求的方法头为空或者不是常规方法,或者请求不指定ContentType且无请求体,返回null
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) || (noContentType && !message.hasBody())) {
return null;
}
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
HttpInputMessage inputMessage = createInputMessage(webRequest);
return readWithMessageConverters(inputMessage, parameter, paramType);
}
protected ServletServerHttpRequest createInputMessage(NativeWebRequest webRequest) {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
return new ServletServerHttpRequest(servletRequest);
}
@Nullable
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
//从请求头获取contentType,如果为空,默认为application/octet-stream
MediaType contentType;
boolean noContentType = false;
try {
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
//contextClass为null
//targetClass为参数的实际类型,例如List<A>,则为A
Class<?> contextClass = parameter.getContainingClass();
Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
if (targetClass == null) {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
targetClass = (Class<T>) resolvableType.resolve();
}
HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
Object body = NO_VALUE;
//对入参HttpInputMessage inputMessage进行简单封装,保存了headers和body InputStream引用
EmptyBodyCheckingHttpInputMessage message;
try {
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
GenericHttpMessageConverter<?> genericConverter =
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
//如果converter是GenericHttpMessageConverter类型,则使用canRead(targetType, contextClass, contentType)判断
//否则使用canRead(targetClass, contentType))判断
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {
//可以转换时
if (message.hasBody()) {
//存在请求头body,则前置Advice().beforeBodyRead方法-> converter.read方法->getAdvice().afterBodyRead方法
HttpInputMessage msgToUse =
getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
}
else {
//否则,执行advice.handleEmptyBody方法
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
}
break;
}
}
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
}
if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
(noContentType && !message.hasBody())) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}
MediaType selectedContentType = contentType;
Object theBody = body;
return body;
}
(2)RequestResponseBodyMethodProcessor
* 调用对应的MessageConverter进行转换,实际调用父类的AbstractMessageConverterMethodProcessor的readWithMessageConverters(见上)
* 如果添加了@Validated/@Valid注解,使用WebDataBinder对转换后返回的参数进行校验,
校验失败时,失败信息会封装到底层的BindingResult中,如果下一个参数不为org.springframework.validation.Error会直接抛出校验失败异常
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
//略
//参数的注解@RequestBody即可
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
//解析处理流程
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//调用对应的MessageConverter进行转换,调用父类的AbstractMessageConverterMethodProcessor的readWithMessageConverters
//如果是json,对应的解析器为MappingJackson2HttpMessageConverter
Object argument = this.readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
//获取解析结果对象的驼峰命名
String name = Conventions.getVariableNameForParameter(parameter);
// 如果添加了@Validated/@Valid注解,使用WebDataBinder对返回参数进行校验
WebDataBinder binder = binderFactory.createBinder(webRequest, argument, name);
if (argument != null) {
//校验失败时,失败信息会封装到底层的BindingResult中,如果下一个参数不为org.springframework.validation.Error会直接抛出校验失败异常
this.validate(binder, parameter);
}
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
return argument;
}
}
判断处理器是否结束(@ResponseStatus/isRequestHandled方法)
* 存在处理器方法上存在@ResponseStatus注解,先执行setResponseStatus处理下@ResponseStatus注解
- 如果注解里有reson属性,使用response.sendError(status.value(), reason);,否则使用response.setStatus(status.value());
- 设置下请求属性:setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
@ResponseStatus(value=HttpStatus.NOT_FOUND,reason="Spittle Not Found")
* 判断处理器是否结束,如果判断需要结束,则设置mavContainer.setRequestHandled(true);
- 当处理器的返回值为null,满足如下3个条件之一,就结束处理
①请求时没有修改,这涉及HTTP的缓存机制,webRequest.isNotModified()
②存在@ResponseStatus注解
③mavContainer已经是结束处理的标志mavContainer.isRequestHandled()
- 当处理器的返回值不为nulL且@ResponseStatus注解里有reason属性,就判断为结束处理
如果结束,就直接return,而不必走后续的流程
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
HttpStatus status = getResponseStatus();
if (status == null) {
return;
}
HttpServletResponse response = webRequest.getResponse();
if (response != null) {
String reason = getResponseStatusReason();
if (StringUtils.hasText(reason)) {
response.sendError(status.value(), reason);
}
else {
response.setStatus(status.value());
}
}
// To be picked up by RedirectView
webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
}
结果处理
* Consumes 限制处理器方法处理指定Content-Type的http请求
* Produces 指定要求处理器方法返回的内容格式,仅当request请求头中的Accept类型中包含该指定类型才返回
* Accept类型代表发送端(客户端)希望接受的数据类型
如果Accept指定了多个MediaType,并且服务端也支持多个MediaType,那么Accept应该同时指定各个MediaType的QualityValue(也就是如图中的q值),服务端根据q值的大小来决定这几个MediaType类型的优先级,一般是大的优先。q值不指定时,默认视为q=1。
例如Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3为Chrome浏览器的默认请求头的值。
主要流程
* 开始进行结果解析处理
- 遍历结果解析器组合,找到第一个支持此控制器方法的解析器HandlerMethodReturnValueHandler
执行解析器handler.supportsReturnType(returnType)
- 调用其HandlerMethodReturnValueHandler.handleReturnValue开始处理
RequestMappingHandlerAdapter.invokeHandleMethod
-> ServletInvocableHandlerMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
//ServletInvocableHandlerMethod类
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
//解析参数、执行处理器方法,返回结果
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
//结果处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {throw ex;}
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
默认的结果解析器列表(顺序由上往下)
(1)基于返回类型的处理
* ModelAndViewMethodReturnValueHandler()
- 支持条件:ModelAndView类型
- 处理处理:如果返回值为null,那么mavContainer.setRequestHandled(true);,结束整个流程
如果不为null,把当前返回值的内容拷贝到上下文mavContainer中即可
* ModelMethodProcessor())
- 支持条件:Model类型
- 处理处理:类似ModelAndViewMethodReturnValueHandler,只拷贝了属性值mavContainer.addAllAttributes(((Model) returnValue).asMap());
* ViewMethodReturnValueHandler()
- 支持条件:View类型
- 处理处理:类似ModelAndViewMethodReturnValueHandler,只拷贝了View值mavContainer.setView(view)/etRedirectModelScenario(true);
* ResponseBodyEmitterReturnValueHandler(getMessageConverters(),this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
- 支持条件:ResponseBodyEmitter 类型
- 处理处理:类似DeferredResult,支持异步处理,底层时长轮询原理
@RequestMapping("/async/responseBodyEmitter")
public ResponseBodyEmitter responseBodyEmitter(){
ResponseBodyEmitter responseBodyEmitter=new ResponseBodyEmitter();
Executors.newSingleThreadExecutor().submit(() -> {
try {
responseBodyEmitter.send("demo");
responseBodyEmitter.send("test");
responseBodyEmitter.complete();
} catch (Exception ignore) {}
});
return responseBodyEmitter;
}
* StreamingResponseBodyReturnValueHandler());
- 支持条件:StreamingResponseBody类型
- 处理处理:直接将结果写出到Response的OutputStream中,使用异步线程池去写入
* HttpEntityMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice));
- 支持条件:HttpEntity类型
- 处理处理:获取结果对象指定的所有请求头
如果是ResponseEntity类型,获取设置的状态码:如果是200且get/head方法且NotModified直接return
调用writeWithMessageConverters对ResponseEntity里封装的结果 T对象转码。处理的流程和@ResponseBody的一样
执行outputMessage.flush();
@RequestMapping(value=)
public ResponseEntity<T> f() throws IOException{
//...
return new ResponseEntity<byte[]>(
T,headers,
HttpStatus.XX);
}
* HttpHeadersReturnValueHandler());
- 支持条件:HttpHeaders类型
- 处理处理:把请求头写入响应流
* CallableMethodReturnValueHandler())
- 支持条件:Callable类型
- 处理处理:WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);
* DeferredResultMethodReturnValueHandler());
- 支持条件:DeferredResult类型
- 处理处理:WebAsyncUtils.getAsyncManager(webRequest).startDeferredResultProcessing(result, mavContainer);
* AsyncTaskMethodReturnValueHandler(this.beanFactory));
- 支持条件:WebAsyncTask类型
- 处理处理:WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer);
(2)基于注解
* ModelAttributeMethodProcessor(false));
- 支持条件:@ModelAttribute标注在方法上
- 处理处理:返回值将会被解释为model的一个属性,mavContainer.addAttribute(name, returnValue);
* RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice));
- 支持条件:@ResponseBody标注在方法上或者类上
- 处理处理:执行其父类的readWithMessageConverters方法进行报文格式转换(见下节)
* ViewNameMethodReturnValueHandler());
- 支持条件:CharSequence(字符串)或者void的返回类型
- 处理处理:如果返回值为CharSequence类型,设置到mavContainer.setViewName(viewName);,否则报错
handlers.add(new MapMethodProcessor());
- 支持条件:Map类型
- 处理处理:如果返回值为Map类型,设置到mavContainer.addAllAttributes((Map) returnValue);;,否则报错
(3)自定义
handlers.addAll(getCustomReturnValueHandlers());
(5)如果在RequestMappingHandlerAdapter中存在用户自己设置的ModelAndViewResolvers
ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
- 支持条件:true
- 处理方式:遍历解析器获取ModelAndView mav = mavResolver.resolveModelAndView(method, handlerType, returnValue, model, webRequest);
设置到当前上下文的mavContainer
不存在,添加ModelAttributeMethodProcessor(true));
- 支持条件:这些类型除外:非Void下的基本类型/Enum/CharSequence/Number/Date/Temporal/URI./URL/Locale/Class
- 处理方式:作为上下文属性mavContainer.addAttribute(name, returnValue);,
name取值规则:Mono<com.myapp.Product> -> productMono
Flux<com.myapp.MyProduct> -> myProductFlux
Observable<com.myapp.MyProduct> -> myProductObservable
RequestResponseBodyMethodProcessor解析@ResponseBody举例
对应的解析器为RequestResponseBodyMethodProcessor

- 主流程
* 外层方法实现
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
//略
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null ||
returnType.getMethodAnnotation(ResponseBody.class) != null);
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException {
mavContainer.setRequestHandled(true);
writeWithMessageConverters(returnValue, returnType, webRequest);
}
}
* writeWithMessageConverters
//转换写原生的webRequest为ServletServerHttpRequest (转换原因见上搜索)
//和封装下ServletServerHttpResponse outputMessage
protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException {
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
//封装下ServletServerHttpResponse outputMessage的原因
ServletResponseHttpHeaders headers,可以设置自己的响应头,如ContentType、CharSet等
写响应时,当原生servletResponse的ContentType/CharacterEncoding为空时,可以根据headers里的值来设置
private void writeHeaders() {
if (!this.headersWritten) {
for (Map.Entry<String, List<String>> entry : this.headers.entrySet()) {
String headerName = entry.getKey();
for (String headerValue : entry.getValue()) {
this.servletResponse.addHeader(headerName, headerValue);
}
}
if (this.servletResponse.getContentType() == null && this.headers.getContentType() != null) {
this.servletResponse.setContentType(this.headers.getContentType().toString());
}
if (this.servletResponse.getCharacterEncoding() == null && this.headers.getContentType() != null &&
this.headers.getContentType().getCharSet() != null) {
this.servletResponse.setCharacterEncoding(this.headers.getContentType().getCharSet().name());
}
this.headersWritten = true;
}
}
* 核心方法writeWithMessageConverters
- 找出请求方期望接收的MIME类型requestedMediaTypes
使用传递进来的内容协商ContentNegotiationManager进行解析request,会遍历注册进来的ContentNegotiationStrategy,
返回第一个不为ALL的,遍历次序如下:
①根据扩展名来判断(默认),比如:mvc/test.xml 将返回xml格式数据
②根据参数来判断 mvc/test?format=xml 将返回xml数据
③根据Http请求的header中的Accept属性的值来判读(默认true),比如:Accept: application/xml 将返回xml格式数据
④服务段默认返回格式,通过在WebMvcConfigurationSupport 子类中configureContentNegotiation方法对configurer.setDefaultContentTypes的设置
- 找出当前处理器方法能返回的MIME类型producibleMediaTypes
①控制器方法@RequestMapping注解produces属性指定的的MediaType集合,存在就直接返回
②如果没有指定,则收集所有支持MediaType为null的messageConverters,在取他们的MediaType作为返回值,使用converter.canWrite(targetType, valueClass, null)
- 对requestedMediaTypes 和producibleMediaTypes 进行一一适配,如果适配不到且处理器方法有非null返回值,则报错
匹配规则,即Accept为json;q=;x=、 product也为json,此时取参数多的一个作为结果
- 选择最佳的类型
按照参数q、精确匹配度、参数大小进行排序,找出第一个精确指定(没有通配符的)的类型作为最终需要转换的类型
如果最终结果为AL或者application,则默认为application/octet-stream
- 遍历所有的messageConverters,找到第一个支持此类型的Converters进行转换,并写入响应流
@SuppressWarnings("unchecked")
protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException {
Class<?> returnValueClass = getReturnValueType(returnValue, returnType);
HttpServletRequest servletRequest = inputMessage.getServletRequest();
//使用传递进来的内容协商ContentNegotiationManager进行解析request,会遍历注册进来的ContentNegotiationStrategy,
//List<MediaType> mediaTypes = strategy.resolveMediaTypes(request);当结果不为ALL时就返回
//处理次序如下:
// 如上的协商策略配置,按照策略按序进行解析,存在即返回MIME类型,返回给客户端
①根据扩展名来判断(默认),比如:mvc/test.xml 将返回xml格式数据
②根据参数来判断 mvc/test?format=xml 将返回xml数据
③根据Http请求的header中的Accept属性的值来判读(默认true),比如:Accept: application/xml 将返回xml格式数据
④服务段默认返回格式,通过在WebMvcConfigurationSupport 子类中configureContentNegotiation方法对configurer.setDefaultContentTypes的设置
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
//控制器方法@RequestMapping注解produces属性指定的的MediaType集合,如果没有指定,则收集所有支持MediaType为null的messageConverters,在取他们的MediaType作为返回值
// 使用converter.canWrite(targetType, valueClass, null)
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass);
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
//以请求需要的类型,一个一个去控制器方法指定的类型配置,如果匹配,说明此处理器方法支持响应请求需要的类型
for (MediaType requestedType : requestedMediaTypes) {
for (MediaType producibleType : producibleMediaTypes) {
//对于匹配的类型,即Accept为json;q=;x=、 product也为json,此时取参数多的一个作为结果
if (requestedType.isCompatibleWith(producibleType)) {
compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
if (compatibleMediaTypes.isEmpty()) {
if (returnValue != null) {
throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
}
return;
}
List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
//按照参数q、精确匹配度、参数大小进行排序,找出第一个精确指定(没有通配符的)的类型作为最终需要转换的类型
MediaType.sortBySpecificityAndQuality(mediaTypes);
MediaType selectedMediaType = null;
for (MediaType mediaType : mediaTypes) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
//遍历所有的messageConverters,找到第一个支持此类型的Converters进行转换,并写入响应流
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
returnValue = this.adviceChain.invoke(returnValue, returnType, selectedMediaType,
(Class<HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage);
if (returnValue != null) {
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
}
return;
}
}
}
if (returnValue != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
获取最终收集的ModelAndView
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
//根据container.getSessionStatus().isComplete()状态是否把@SeesionAttribute的属性从当前request
//把BindingResult结果放到Model
modelFactory.updateModel(webRequest, mavContainer);
//处理器是否结果,是返回null
if (mavContainer.isRequestHandled()) {
return null;
}
//把上下文收到的mavContainer的说要信息封装到一个新的ModelAndView返回
ModelMap model = mavContainer.getModel();
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
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;
}
执行拦截器链的后置方法
使用HandlerExecutionChain的applyPreHandle方法
* 获取当前HandlerExecutionChain处理器执行链的配置的拦截器集合
* 逆序遍历每一个拦截器的applyPostHandle
@Nullable
public HandlerInterceptor[] getInterceptors() {
if (this.interceptors == null && this.interceptorList != null) {
this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);
}
return this.interceptors;
}
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
if (getInterceptors() == null) {
return;
}
for (int i = getInterceptors().length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = getInterceptors()[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)