[Original] 006 | catch SpringBoot parameter parsing the return value of the processing source code analysis car

Part VI Benpian analysis of springboot Source: SpringBoot parameter parsing the return value of the processing source code, we welcome the review, Tucao, and thumbs share.

This car series of articles (click on the title to jump)

[Original] 001 | catch SpringBoot automatic injection source code analysis car

[Original] 002 | catch SpringBoot affairs source code analysis car

[Original] 003 | SpringBoot Affairs idea to catch on real car

[Original] 004 | catch SpringBoot Affairs strange car event analysis

[Original] 005 | catch SpringBoot request processing source code analysis car

Car introduced

The trip is bound SpringBoot car return value and parameter parsing source code analysis process

Car problem

The first question: SpringBoot is how to parse the parameters web request?

The second question: SpringBoot is how to handle the return value of web requests?

Examples of car

The first step: define the interface

@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);
}
复制代码

Step two: Defining interface

@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;
    }
}
复制代码

Source take new method is exemplified to explain SpringBoot by this example is how to parse the request parameters and injected into the Person object is how to handle and List

Car analysis

In SpringBoot requests source analysis car another object is RequestMappingHandlerAdapter, to process the request, described herein is the focus of the analysis; mentioned two important objects, one RequestMappingHandlerMapping, mapping to process the request

First, let's look at the creation achieve RequestMappingHandlerAdapter

创建RequestMappingHandlerAdapter:WebMvcAutoConfiguration.EnableWebMvcConfiguration#requestMappingHandlerAdapter

@Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
    RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
    adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
                                            || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
    return adapter;
}
复制代码

Call the parent class to create 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;
}
复制代码

As there is a message to the object settings RequestMappingHandlerAdapter converters, these converters are messages created?

Gets the message converter: 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;
}
复制代码

Add default message converter: 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()));
    }
}
复制代码

Here you can see a lot of news to add converter, eventually these messages converters assigned to the RequestMappingHandlerAdapter object messageConverters property

Since RequestMappingHandlerAdapter realized InitializingBean interface, then after the bean is created afterPropertiesSet method will call some initialization

Initialization: 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);
    }
}
复制代码

As seen parser parameters, return values ​​of two parts processor, to which a little taste, at least, to see the signs point, do not worry, we stop and slowly analysis

Get the default parser list of parameters: 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;
}
复制代码

As you can see to create a parameter annotation parser, foundation type parameter parser, and add a custom parser

Returns a value obtained Processor: 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;
}
复制代码

The same return value to create a series of processors

This, the parser parameters and return values ​​processors have been created and assigned to the RequestMappingHandlerAdapter objects, with parameters and return values ​​parser processor, then you can parse request parameters, return values ​​of processing the request. Then take a look at how the processing of the request using the parameter and return value parser processor.

Request Processing

Call processing method: 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();
    }
}
复制代码

And process execution request Return Value: 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;
    }
}
复制代码

Execution request

Execution of the request: 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);
}
复制代码

Analytical method parameters: 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;
}
复制代码

Why qualifying parameter parser is RequestResponseBodyMethodProcessor

@Override
public boolean supportsParameter(MethodParameter parameter) {
    return parameter.hasParameterAnnotation(RequestBody.class);
}
复制代码

You can see the argument parser used to parse notes with @RequestBody modified parameter information

Use parameter parser parameters: 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);
}
复制代码

A converter to read parameter information:

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;
}
复制代码

The message converter to read data: 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);
    }
}
复制代码

Parameter read request concludes this portion returns to the execution request code

Execution of the request: 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);
}
复制代码

After the return to get the data, the next step is how to deal with the return value

Process the return value

Request and process: 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;
    }
}
复制代码

Use the return value processor Return Value: 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);
}
复制代码

Select the return value processor: 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;
}
复制代码

Why is RequestResponseBodyMethodProcessor meet the requirements of the return value processor?

@Override
public boolean supportsReturnType(MethodParameter returnType) {
    // 如果所在的类含有@ResponseBody注解或者方法含有@ResponseBody注解,返回true
    return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
            returnType.hasMethodAnnotation(ResponseBody.class));
}
复制代码

Use the return value handling the return value: 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);
}
复制代码

Converter converts return data message: 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);
    }
}
复制代码

The return value is also the end of this processing section

Car review

The first question: SpringBoot is how to parse request parameters? First creates a series of messages converter, and then create a series of processors, the processor comprising a message converter, to find the corresponding processor at request, and then find the corresponding request according to the type of converter, the parameters resolve

The second question: SpringBoot is how to handle requests return value? Same message converter, return value processor, according to the identifier corresponding to the selection processor returns to find the corresponding message converter, then the message converter write data to the client.

Car summary

  • Objects created RequestMappingHandlerAdapter
  • Set message converter
  • AfterPropertiesSet initialization parameters parser initialization process, the return value processor
  • ServletInvocableHandlerMethod create an object, set the parameter parser, the return value processor
  • Use RequestResponseBodyMethodProcessor MappingJackson2HttpMessageConverter parameter parser reads the message parameter converter
  • Returns the value of the processor using RequestResponseBodyMethodProcessor MappingJackson2HttpMessageConverter message conversion processing return value


Guess you like

Origin juejin.im/post/5de08d68f265da05f84bba91