[オリジナル] 006 |処理ソースコード解析の車の戻り値を解析キャッチSpringBootパラメータ

springbootソースのパートVI Benpian解析:処理のソースコードの戻り値を解析パラメータSpringBootは、我々は、レビュー、Tucao、と親指シェアを歓迎します。

記事のこの車シリーズ(ジャンプのタイトルをクリックしてください)

[オリジナル] 001 |キャッチSpringBoot自動注入ソースコード解析の車

[オリジナル] 002 |キャッチSpringBoot情勢のソースコード解析の車

[オリジナル] 003 |本物の車のキャッチにSpringBoot総務アイデア

[オリジナル] 004 |キャッチSpringBoot総務奇妙な車のイベント分析

[オリジナル] 005 |キャッチSpringBoot要求処理のソースコード解析の車

カー導入

旅行はバウンドSpringBoot車の戻り値とパラメータは、ソースコード解析プロセスを解析しています

車の問題

最初の質問:SpringBootがパラメータのWeb要求を解析する方法ですか?

2番目の質問:SpringBootは、Web要求の戻り値を処理する方法ですか?

車の例

最初のステップ:インタフェースを定義

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

ステップ2:インタフェースの定義

@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オブジェクトに注入して処理して一覧にする方法であります

車の分析

SpringBootソース解析車を要求するリクエストを処理するために、他の目的はRequestMappingHandlerAdapterあり、本明細書に記載の解析の焦点である、二つの重要なオブジェクト一RequestMappingHandlerMappingを述べ、要求を処理するようにマッピングします

まず、作成時に見てみましょうは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はリクエストパラメータを解析する方法ですか?最初は、メッセージ変換のシリーズを作成し、プロセッサのシリーズを作成し、要求に対応するプロセッサを見つけ、その後、コンバータの種類、パラメータに従って、対応する要求を見つけるために、メッセージ・コンバータを含むプロセッサ決意

2番目の質問:SpringBootがリクエストの戻り値を処理する方法ですか?クライアントに同じメッセージコンバータ、戻り値のプロセッサ、対応するメッセージ変換を見つけるために、選択プロセッサ復帰に対応する識別子に応じて、メッセージ変換書き込みデータ。

車の概要

  • RequestMappingHandlerAdapterを作成されたオブジェクト
  • 集合メッセージコンバータ
  • AfterPropertiesSet初期化パラメータパーサ初期化プロセス、戻り値プロセッサ
  • オブジェクトを作成するServletInvocableHandlerMethod、パラメータパーサ、戻り値のプロセッサを設定します
  • 使用RequestResponseBodyMethodProcessor MappingJackson2HttpMessageConverterパラメータパーサは、メッセージパラメータコンバータを読み込み
  • RequestResponseBodyMethodProcessor MappingJackson2HttpMessageConverterメッセージ変換処理の戻り値を使用して、プロセッサの値を返します


おすすめ

転載: juejin.im/post/5de08d68f265da05f84bba91