今天工作的时候,一不小心就对spring如何通过注解来解析请求好奇了。
查询了资料,spring mvc请求处理大致是这样子的,由DispatcherServlet截获请求,DispatcherServlet通过handlerMappng得到HandlerExecutionChain。然后获得HandlerAdapter。
HandlerAdapter内部对于每个请求生成一个ServletInvocableHandlerMethod进行处理。而ServletInvocableHandlerMethod处理时会分成请求和响应两部分进行。然后ServletInvocableHandlerMethod得到ModelAndView进行处理。
1. 处理请求的时候,会根据ServletInvocableHandlerMethod的属性argumentResolvers(这个属性是它的父类InvocableHandlerMethod中定义的)进行处理,其中argumentResolvers属性是一个HandlerMethodArgumentResolverComposite类(这里使用了组合模式的一种变形),这个类是实现了HandlerMethodArgumentResolver接口的类,里面有各种实现了HandlerMethodArgumentResolver的List集合。
- 处理响应的时候,会根据ServletInvocableHandlerMethod的属性returnValueHandlers(自身属性)进行处理,returnValueHandlers属性是一个HandlerMethodReturnValueHandlerComposite类(这里使用了组合模式的一种变形),这个类是实现了HandlerMethodReturnValueHandler接口的类,里面有各种实现了HandlerMethodReturnValueHandler的List集合。
ServletInvocableHandlerMethod的returnValueHandlers和argumentResolvers这两个属性都是在ServletInvocableHandlerMethod进行实例化的时候被赋值的(使用RequestMappingHandlerAdapter的属性进行赋值)。
RequestMappingHandlerAdapter的argumentResolvers和returnValueHandlers这两个属性是在RequestMappingHandlerAdapter进行实例化的时候被Spring容器注入的。
其中默认的ArgumentResolvers:
默认的returnValueHandlers:
使用@ResponseBody注解的话最终返回值会被RequestResponseBodyMethodProcessor这个HandlerMethodReturnValueHandler实现类处理。
我们通过源码发现,RequestResponseBodyMethodProcessor这个类其实同时实现了HandlerMethodReturnValueHandler和HandlerMethodArgumentResolver这两个接口。
RequestResponseBodyMethodProcessor支持的请求类型是Controller方法参数中带有@RequestBody注解,支持的响应类型是Controller方法带有@ResponseBody注解。
RequestResponseBodyMethodProcessor响应的具体处理是使用消息转换器。
处理请求的时候使用内部的readWithMessageConverters方法。
然后会执行父类(AbstractMessageConverterMethodArgumentResolver)的readWithMessageConverters方法。
“`java
protected Object readWithMessageConverters(NativeWebRequest webRequest,
MethodParameter methodParam, Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
final HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
HttpInputMessage inputMessage = new ServletServerHttpRequest(servletRequest);
InputStream inputStream = inputMessage.getBody();
if (inputStream == null) {
return handleEmptyBody(methodParam);
}
else if (inputStream.markSupported()) {
inputStream.mark(1);
if (inputStream.read() == -1) {
return handleEmptyBody(methodParam);
}
inputStream.reset();
}
else {
final PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
int b = pushbackInputStream.read();
//如果返回的值是空的
if (b == -1) {
//检查有没有Responsebody注解,有抛出一个异常
return handleEmptyBody(methodParam);
}
else {
pushbackInputStream.unread(b);
}
inputMessage = new ServletServerHttpRequest(servletRequest) {
@Override
public InputStream getBody() throws IOException {
// Form POST should not get here
return pushbackInputStream;
}
};
}
//有数据,则调用父类的方法
return super.readWithMessageConverters(inputMessage, methodParam, paramType);
}
java
父类的方法readWithMessageConverters,通过对应的media的类型调用HttpMessageConverter方法,遍历并且使用了Read方法。
protected Object readWithMessageConverters(HttpInputMessage inputMessage,
MethodParameter methodParam, Type targetType) throws IOException, HttpMediaTypeNotSupportedException {
MediaType contentType;
try {
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
Class<?> contextClass = methodParam.getContainingClass();
for (HttpMessageConverter<?> converter : this.messageConverters) {
if (converter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
if (genericConverter.canRead(targetType, contextClass, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Reading [" + targetType + "] as \"" +
contentType + "\" using [" + converter + "]");
}
return genericConverter.read(targetType, contextClass, inputMessage);
}
}
Class<T> targetClass = (Class<T>)
ResolvableType.forMethodParameter(methodParam, targetType).resolve(Object.class);
if (converter.canRead(targetClass, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Reading [" + targetClass.getName() + "] as \"" +
contentType + "\" using [" + converter + "]");
}
return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
}
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}
“`