本篇爲springboot源碼分析的第六篇:SpringBoot參數解析返回值處理源碼,歡迎你們檢閱,吐槽,以及點贊分享。
java
【原創】001 | 搭上SpringBoot自動注入源碼分析專車
react
【原創】002 | 搭上SpringBoot事務源碼分析專車
web
【原創】003 | 搭上基於SpringBoot事務思想實戰專車spring
【原創】004 | 搭上SpringBoot事務詭異事件分析專車json
【原創】005 | 搭上SpringBoot請求處理源碼分析專車
springboot
該趟是開往SpringBoot參數解析和返回值處理源碼分析的專車bash
第一個問題:SpringBoot是如何解析web請求的參數?mvc
第二個問題:SpringBoot是如何處理web請求的返回值?app
第一步:定義接口異步
@RequestMapping("/persons")
public interface PersonApi {
/**
* list
*
* @return
*/
@GetMapping("/")
List<Person> list();
/**
* get
*
* @param id
* @return
*/
@GetMapping("/{id}")
Person get(@PathVariable("id") Integer id);
/**
* add
*
* @param person
* @return
*/
@PostMapping("/")
List<Person> add(@Valid @RequestBody Person person);
/**
* update
*
* @param person
* @return
*/
@PutMapping("/")
List<Person> update(@RequestBody Person person);
}
複製代碼
第二步:定義接口實現
@RestController
public class PersonController implements PersonApi {
private static List<Person> personList = new ArrayList<>();
static {
personList.add(new Person(10001, "test1"));
personList.add(new Person(10002, "test2"));
personList.add(new Person(10003, "test3"));
personList.add(new Person(10004, "test4"));
personList.add(new Person(10005, "test5"));
}
@Override
public List<Person> list() {
return personList;
}
@Override
public Person get(Integer id) {
Person defaultPerson = new Person(88888, "default");
return personList.stream().filter(person -> Objects.equals(person.getId(), id)).findFirst().orElse(defaultPerson);
}
@Override
public List<Person> add(Person person) {
personList.add(person);
return personList;
}
@Override
public List<Person> update(Person person) {
personList.removeIf(p -> Objects.equals(p.getId(), person.getId()));
personList.add(person);
return personList;
}
}
複製代碼
源碼拿新增方法來舉例,經過該示例來說解SpringBoot是如何解析請求參數並注入到Person對象中的以及是如何處理值List
在SpringBoot請求源碼分析專車中提到兩個重要的對象,一個是RequestMappingHandlerMapping,用來處理請求映射;另外一個是RequestMappingHandlerAdapter,用來處理請求,也是本文重點分析的對象
首先來看看RequestMappingHandlerAdapter的建立實現
建立RequestMappingHandlerAdapter:WebMvcAutoConfiguration.EnableWebMvcConfiguration#requestMappingHandlerAdapter
@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
|| this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}
複製代碼
調用父類建立RequestMappingHandlerAdapter:WebMvcConfigurationSupport#requestMappingHandlerAdapter
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
// 建立RequestMappingHandlerAdapter
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(mvcContentNegotiationManager());
// 設置消息轉換器
adapter.setMessageConverters(getMessageConverters());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
// 設置自定義參數解析器
adapter.setCustomArgumentResolvers(getArgumentResolvers());
// 設置自定義返回值處理器
adapter.setCustomReturnValueHandlers(getReturnValueHandlers());
// 若是存在jackson
if (jackson2Present) {
// 設置requestBody通知
adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
// 設置responseBody通知
adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
// ...省略部分代碼
return adapter;
}
複製代碼
如上有給RequestMappingHandlerAdapter對象設置消息轉換器,那麼這些消息轉換器是建立的?
獲取消息轉換器:WebMvcConfigurationSupport#getMessageConverters
protected final List<HttpMessageConverter<?>> getMessageConverters() {
if (this.messageConverters == null) {
this.messageConverters = new ArrayList<>();
configureMessageConverters(this.messageConverters);
if (this.messageConverters.isEmpty()) {
// 添加默認消息轉換器
addDefaultHttpMessageConverters(this.messageConverters);
}
extendMessageConverters(this.messageConverters);
}
return this.messageConverters;
}
複製代碼
添加默認消息轉換器:WebMvcConfigurationSupport#addDefaultHttpMessageConverters
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316
messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(stringHttpMessageConverter);
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
try {
messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Throwable ex) {
// Ignore when no TransformerFactory implementation is available...
}
messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
messageConverters.add(new AtomFeedHttpMessageConverter());
messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
}
else if (jaxb2Present) {
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
messageConverters.add(new JsonbHttpMessageConverter());
}
if (jackson2SmilePresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
}
if (jackson2CborPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
}
}
複製代碼
能夠看到此處添加了不少的消息轉換器,最終這些消息轉換器賦值給了RequestMappingHandlerAdapter對象的messageConverters屬性
因爲RequestMappingHandlerAdapter實現了InitializingBean接口,那麼在該bean建立完成後會調用afterPropertiesSet方法進行一些初始化操做
初始化操做:RequestMappingHandlerAdapter#afterPropertiesSet
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache();
if (this.argumentResolvers == null) {
// 獲取默認的參數解析器列表
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
// 建立方法參數解析器對象
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
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);
}
}
複製代碼
如上看到參數解析器、返回值處理器兩部份內容,到這就有點味道了,起碼看到了點苗頭,別急,咱們靜下心來慢慢分析
獲取默認的參數解析器列表:RequestMappingHandlerAdapter#getDefaultArgumentResolvers
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
// 此處將以前的消息轉換器賦值給了該參數解析器,後續會使用到
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
複製代碼
如上能夠看到建立了註解參數解析器、基礎類型參數解析器,並添加了自定義解析器
獲取返回值處理器:RequestMappingHandlerAdapter#getDefaultReturnValueHandlers
private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
// Single-purpose return value types
handlers.add(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
handlers.add(new StreamingResponseBodyReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler());
handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
// Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
// 注意此處將消息轉換器賦值給了該返回值處理器對象
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));
// Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());
// Custom return value types
if (getCustomReturnValueHandlers() != null) {
handlers.addAll(getCustomReturnValueHandlers());
}
// Catch-all
if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
handlers.add(new ModelAttributeMethodProcessor(true));
}
return handlers;
}
複製代碼
一樣的建立一系列的返回值處理器
到此,參數解析器和返回值處理器都已經建立好,並賦值給了RequestMappingHandlerAdapter對象,有了參數解析器和返回值處理器,那麼就能夠解析請求參數、處理請求返回值了。接下來就看看請求處理過程當中是如何使用參數解析器和返回值處理器的。
調用處理方法:RequestMappingHandlerAdapter#invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 使用handlerMethod對象來構建ServletInvocableHandlerMethod對象,也就是完成屬性的賦值,此對象很重要,後續的全部操做都和該對象有關
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
// 將以前的參數解析器對象賦值給ServletInvocableHandlerMethod對象
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
// 將以前的返回值處理器對象賦值給ServletInvocableHandlerMethod對象
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// ...省略部分代碼
// 執行請求並處理返回值
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
複製代碼
執行請求並處理返回值:ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 執行請求
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
// ...省略部分代碼
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 處理返回結果
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
複製代碼
執行請求:InvocableHandlerMethod#invokeForRequest
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 解析方法參數列表信息
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 執行目標方法
return doInvoke(args);
}
複製代碼
解析方法參數:InvocableHandlerMethod#getMethodArgumentValues
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 獲取方法參數對象列表信息
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 遍歷全部的參數解析器,若是全部的參數解析器都沒法解析該參數,直接報錯
// 此處符合條件的參數解析器爲RequestResponseBodyMethodProcessor
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 使用RequestResponseBodyMethodProcessor參數解析器來解析當前參數信息
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
// ... 省略部分代碼
}
return args;
}
複製代碼
爲何符合條件的參數解析器爲RequestResponseBodyMethodProcessor
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
複製代碼
能夠看到該參數解析器用來解析用@RequestBody註解修飾的參數信息
使用參數解析器解析參數:RequestResponseBodyMethodProcessor#resolveArgument
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
// 使用消息轉換器讀取參數信息
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
// ...省略部分代碼
return adaptArgumentIfNecessary(arg, parameter);
}
複製代碼
使用轉換器讀取參數信息:
AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters(org.springframework.http.HttpInputMessage, org.springframework.core.MethodParameter, java.lang.reflect.Type)
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
MediaType contentType;
boolean noContentType = false;
try {
// 從請求頭中讀取請求的類型,好比application/json
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
// 若是請求類型爲空,默認請求類型爲application/octet-stream,請求的是一個二進制流
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
// 參數類型
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;
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);
// 因爲咱們的請求類型爲application/json,因此此處能夠讀取數據的消息轉換器爲MappingJackson2HttpMessageConverter
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {
if (message.hasBody()) {
// ...省略部分代碼
// 使用MappingJackson2HttpMessageConverter讀取數據並返回
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
// ...省略部分代碼
}
else {
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
}
break;
}
}
}
// ...省略部分代碼
return body;
}
複製代碼
消息轉換器讀取數據:AbstractJackson2HttpMessageConverter#readJavaType
private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException {
try {
// ...省略部分代碼
// 使用jackson從請求體中讀取數據
return this.objectMapper.readValue(inputMessage.getBody(), javaType);
}
catch (InvalidDefinitionException ex) {
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
}
catch (JsonProcessingException ex) {
throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex, inputMessage);
}
}
複製代碼
讀取請求參數的部分到此就結束了,返回到執行請求的代碼
執行請求:InvocableHandlerMethod#invokeForRequest
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 解析並獲取到方法參數信息
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 利用反射來調用目標方法,獲取方法的返回值
return doInvoke(args);
}
複製代碼
拿到返回數據以後,接下來就是如何處理返回值
請求並處理:ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// ...省略部分代碼
try {
// 使用返回值處理器來處理返回值
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
複製代碼
使用返回值處理器處理返回值:HandlerMethodReturnValueHandlerComposite#handleReturnValue
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 選擇返回值處理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
// 若是返回值處理器爲空,直接拋出異常
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
// 使用返回值處理器處理返回值
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
複製代碼
選擇返回值處理器:HandlerMethodReturnValueHandlerComposite#selectHandler
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
// 是否爲異步返回值
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
// 遍歷全部的返回值處理器
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
// 若是當前返回值處理器支持當前返回值類型,直接返回。此處符合要求的是RequestResponseBodyMethodProcessor處理器
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
複製代碼
爲何符合要求的是RequestResponseBodyMethodProcessor返回值處理器?
@Override
public boolean supportsReturnType(MethodParameter returnType) {
// 若是所在的類含有@ResponseBody註解或者方法含有@ResponseBody註解,返回true
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
複製代碼
使用返回值處理返回值:RequestResponseBodyMethodProcessor#handleReturnValue
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
複製代碼
消息轉換器轉換返回數據:AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse)
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Object body;
Class<?> valueType;
Type targetType;
// ...省略部分代碼
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
// 遍歷消息轉換器,找到合適的消息轉換器將數據寫到客戶端
for (HttpMessageConverter<?> converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
// ...省略部分代碼
if (body != null) {
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn ->
"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
addContentDispositionHeader(inputMessage, outputMessage);
if (genericConverter != null) {
// 將數據寫回客戶端
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
} else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
// ...省略部分代碼
return;
}
}
}
if (body != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
複製代碼
返回值處理部分到此也結束了
第一個問題:SpringBoot是如何解析請求參數的?首先會建立一系列的消息轉換器,而後在建立一系列的處理器,處理器中包含了消息轉換器,在請求的時候找到對應的處理器,而後根據請求類型找到對應的轉換器,進行參數解析
第二個問題:SpringBoot是如何處理請求返回值?一樣是消息轉換器,返回值處理器,根據返回的標識選擇對應的處理器,找到相應的消息轉換器,而後使用消息轉換器往客戶端寫數據。