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注册自定义适配器替换默认的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值