RequestMappingHandlerAdapter源码解析
构造方法
//构造方法初始化消息转换器
public RequestMappingHandlerAdapter() {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316
this.messageConverters = new ArrayList<>(4);
//字节流数组转换器:读写字节流数组,默认支持所有的媒体类型,写出Content-Type=application/octet-stream类型
this.messageConverters.add(new ByteArrayHttpMessageConverter());
//字符串转换器,同上一个,写出Content-Type=text/plain类型
this.messageConverters.add(stringHttpMessageConverter);
//支持text/xml application/xml application/*-xml类型
this.messageConverters.add(new SourceHttpMessageConverter<>());
//支持xml JSON
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
初始化流程
该类实现了InitializingBean接口,由spring创建默认对象后会回调改接口的方法进行初始化,初始化流程如下:
@Override
public void afterPropertiesSet() {
//初始化controller的切面@ControllerAdvice,例如添加ResponseBody切面类
initControllerAdviceCache();
//获取所有默认的方法请求参数解析器(包括自定义和内置的),赋值给this.argumentResolvers变量
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
//获取所有针对@InitBinder注解方法的请求参数解析器(包括自定义和内置)
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);
}
}
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
if (logger.isInfoEnabled()) {
logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
}
//获取所有@ControllerAdvice注解标记的Bean,封装切面信息到ControllerAdviceBean中
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
AnnotationAwareOrderComparator.sort(adviceBeans);
List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
//循环处理切面类
for (ControllerAdviceBean adviceBean : adviceBeans) {
Class<?> beanType = adviceBean.getBeanType();
if (beanType == null) {
throw new IllegalStateException("...." + adviceBean);
}
//收集所有@ModelAttribute注解(前端视图相关)标记,但是没有@RequestMapping注解标记的方法
Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
if (logger.isInfoEnabled()) {
logger.info("Detected @ModelAttribute methods in " + adviceBean);
}
}
//收集所有@InitBinder注解的方法:该注解用于前端表单数据绑定
Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(adviceBean, binderMethods);
if (logger.isInfoEnabled()) {
logger.info("Detected @InitBinder methods in " + adviceBean);
}
}
//收集所有RequestBodyAdvice接口实现类(扩展点)
if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
requestResponseBodyAdviceBeans.add(adviceBean);
if (logger.isInfoEnabled()) {
logger.info("Detected RequestBodyAdvice bean in " + adviceBean);
}
}
//收集所有ResponseBodyAdvice接口实现类(扩展点)
if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
requestResponseBodyAdviceBeans.add(adviceBean);
if (logger.isInfoEnabled()) {
logger.info("Detected ResponseBodyAdvice bean in " + adviceBean);
}
}
}
//this.requestResponseBodyAdvice变量持有所有的ResponseBody的切面
if (!requestResponseBodyAdviceBeans.isEmpty()) {
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
}
由上面源码可知,出现了两个扩展点接口如下:
public interface RequestBodyAdvice
这个接口允许对请求体被读取并被转换器转换成对象前做一些操作,
同时允许转换成对象后还没有传递给controller前做一些操作
public interface ResponseBodyAdvice
该接口允许方法返回值被写出响应前做一些操作
以上两个接口的只需要实现接口,用@conponent注解标记让spring容器管理,
同时使用@ControllerAdvice声明为controller切面
初始化流程中还要关注收集参数解析器和返回值解析器过程,源码如下:
收集参数解析器,涉及使用的注解:@RequestParam @PathVariable @MatrixVariable @ModelAttribute @RequestBody @RequestPart
@RequestHeader @CookieValue @Value @SessionAttribute
//获取所有默认的方法请求参数解析器(包括自定义和内置的)
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
//EL表达式解析器
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
//解析方法参数是Map类型且使用@RequestParam注解,将参数以key-value形式全部封装到map中
//例如方法:public Map getMap(@RequestParam HashMap map)
resolvers.add(new RequestParamMapMethodArgumentResolver());
//@PathVariable注解的参数解析器
resolvers.add(new PathVariableMethodArgumentResolver());
//解析方法参数是Map类型且使用@PathVariable注解,将参数以key-value形式全部封装到map中
resolvers.add(new PathVariableMapMethodArgumentResolver());
//@MatrixVariable注解的参数解析器
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
//@ModelAttribute注解方法入参解析处理
resolvers.add(new ServletModelAttributeMethodProcessor(false));
//处理使用@RequestBody注解绑定入参
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyA.requestResponseBodyAdvice));
//处理使用@RequestPart注解绑定入参
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAd.requestResponseBodyAdvice));
//处理使用@RequestHeader注解绑定请求头入参
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
//处理使用@CookieValue注解入参绑定cookie
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
//处理使用@Value注解入参绑定容器中的值
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
//处理使用@SessionAttribute注解入参绑定session中的值
resolvers.add(new SessionAttributeMethodArgumentResolver());
//处理使用@RequestAttribute注解入参绑定requst中的值
resolvers.add(new RequestAttributeMethodArgumentResolver());
//处理方法入参注入WebRequest ServletRequest MultipartRequest HttpSession InputStream等对象
resolvers.add(new ServletRequestMethodArgumentResolver());
//处理方法注入ServletResponse OutputStream Writer 等接口子类对象
resolvers.add(new ServletResponseMethodArgumentResolver());
//处理入参类型是HttpEntity RequestEntity 类型
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
//处理入参是RedirectAttributes类型(跟ModelAndView有关)
resolvers.add(new RedirectAttributesMethodArgumentResolver());
//处理入参是Model类型(将ModelAndView中参数封装到Model中)
resolvers.add(new ModelMethodProcessor());
//处理入参是Map类型(将ModelAndView中参数封装到map中)
resolvers.add(new MapMethodProcessor());
//处理入参是Errors类型:例如 BindingResult类 MapBindingResult类
resolvers.add(new ErrorsMethodArgumentResolver());
//注入SessionStatus参数
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<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
//ModelAndView类型返回值处理器
handlers.add(new ModelAndViewMethodReturnValueHandler());
//Model类型返回值处理器
handlers.add(new ModelMethodProcessor());
//View类型返回值处理器
handlers.add(new ViewMethodReturnValueHandler());
//处理ResponseBodyEmitter 及其子类 SseEmitter和ResponseEntity封装的该类,跟异步编程模型有关
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
//处理StreamingResponseBody ResponseEntity<StreamingResponseBody>返回值,异步编程相关
handlers.add(new StreamingResponseBodyReturnValueHandler());
//处理HttpEntity类及其子类的返回值,但是不能是RequestEntity子类类型
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
//处理HttpHeaders类返回值
handlers.add(new HttpHeadersReturnValueHandler());
//处理Callable类异步任务返回值,会封装成一个异步任务回调执行
handlers.add(new CallableMethodReturnValueHandler());
//处理DeferredResult ListenableFuture CompletionStage三类返回值,跟异步编程返回结果有关
handlers.add(new DeferredResultMethodReturnValueHandler());
//处理WebAsyncTask返回值,跟异步任务有关
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
//处理@ModelAttribute注解方法返回值
handlers.add(new ModelAttributeMethodProcessor(false));
//处理使用了@ResponseBody的类或者方法的返回值
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
//处理返回值是视图名称(方法返回为void或字符串)
handlers.add(new ViewNameMethodReturnValueHandler());
//处理返回值是Map类型
handlers.add(new MapMethodProcessor());
//收集自定义的返回值处理器
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
//兜底返回值处理器
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}else {
handlers.add(new ModelAttributeMethodProcessor(true));
}
return handlers;
}
扩展总结
方法入参绑定使用注解和默认支持注入对象:
//这个三个都存在绑定Map的特别情况
@RequestParam
@PathVariable
@MatrixVariable
@ModelAttribute //前端传值相关
@RequestBody //处理JSON返回值
@RequestPart //可以处理文件上传,与@RequestParam一样,能处理更复杂场景
//以下四个个注解绑定servlet域对象中的值
@RequestHeader
@RequestAttribute
@CookieValue
@SessionAttribute
@Value //该注解将入参绑定spring容器中的对象
//以下是方法入参默认支持和注入的对象
//以下与请求相关对象由ServletRequestMethodArgumentResolver类解析注入
WebRequest
ServletRequest
MultipartRequest
HttpSession
Principal
InputStream
Reader
HttpMethod
Locale
TimeZone
ZoneId
//以下响应相关对象由 ServletResponseMethodArgumentResolver解析注入
ServletResponse
OutputStream
Writer
// HttpEntityMethodProcessor处理
HttpEntity
RequestEntity
扩展接口开发
//请求切面接口,干预请求体转换成对象前后,配合@ControllerAdvice注解使用
public interface RequestBodyAdvice
可以通过继承RequestBodyAdviceAdapter实现
//响应体切面,响应写回去前操作,配合@ControllerAdvice注解使用
public interface ResponseBodyAdvice
// 自定义方法参数解析器,排序在内置的解析器之后,通过实现WebMvcConfigurer接口添加组件
public interface HandlerMethodArgumentResolver
//自定义方法返回值处理器,排序在内置的解析器之后,通过实现WebMvcConfigurer接口添加组件
public interface HandlerMethodReturnValueHandler
方法参数和返回值解析器,只能各选择一个,按照排序的顺序进行遍历匹配,匹配到前面的选中,后面的就不会使用执行了。
扩展RequestMappingHandlerAdapter功能,重写类继承RequestMappingHandlerAdapter,重写相关方法进行定制化处理器适配器。
通过实现WebMvcRegistrations注册自定义适配器替换默认的。