• springmvc@RequestBody原理及扩展


    深入理解@RequestBody原理

    一、RequestBody注解概述

    我们通常使用RequestBody注解来web请求中的body体部分内容,并且通常会将其转换为一个javaBean的对象!

    如下面的示例文件:

        @PostMapping("/school")
        public School querySchool(@RequestBody School school){
            return school;
        }
    
    • 1
    • 2
    • 3
    • 4
    @Data
    public class School {
        private String name;
    }
    
    • 1
    • 2
    • 3
    • 4

    示例对象依赖的POM文件为:

    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0modelVersion>
        <parent>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-parentartifactId>
            <version>2.6.3version>
            <relativePath/> 
        parent>
        <groupId>com.examplegroupId>
        <artifactId>rsa-sign-demoartifactId>
        <version>0.0.1-SNAPSHOTversion>
        <name>rsa-sign-demoname>
        <description>rsa-sign-demodescription>
        <properties>
            <java.version>1.8java.version>
        properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            <dependency>
                <groupId>org.apache.commonsgroupId>
                <artifactId>commons-lang3artifactId>
            dependency>
    
            <dependency>
                <groupId>commons-iogroupId>
                <artifactId>commons-ioartifactId>
                <version>2.4version>
            dependency>
    
    
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starterartifactId>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
            dependency>
        dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                    <version>2.6.3version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackagegoal>
                            goals>
                        execution>
                    executions>
    
                plugin>
            plugins>
        build>
    project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    通过Postman发送请求,得到结果如下:

    请求后台

    那么springMVC是如何将Body体中的内容绑定到实体对象School中去的呢?

    requestBody注解类注释:

    Annotation indicating a method parameter should be bound to the body of the web request.
    The body of the request is passed through an {@link HttpMessageConverter} to resolve the method argument depending on the content type of the request.
    
    • 1
    • 2

    从上面的描述我们可以看到主要是通过HttpMessageConverter来进行转换,

    二、执行流程

    所有的springmvc请求都会经过org.springframework.web.servlet.DispatcherServlet#doDispatch来进行处理,我们就从该方法开始跟踪。主要流程图如下所示:

    在这里插入图片描述

    2.1、DispatcherServlet处理

    doDispatch方法中的源码如下,只保留我们想进行关注的部分代码:

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    		HttpServletRequest processedRequest = request;
    		HandlerExecutionChain mappedHandler = null;
    		boolean multipartRequestParsed = false;
    
    		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
    		try {
    			ModelAndView mv = null;
    			Exception dispatchException = null;
    
    			try {
    				processedRequest = checkMultipart(request);
    				multipartRequestParsed = (processedRequest != request);
    
    				// Determine handler for the current request.
                    //根据请求来来获取对应的处理器
    				mappedHandler = getHandler(processedRequest);
    				if (mappedHandler == null) {
    					noHandlerFound(processedRequest, response);
    					return;
    				}
    
    				// Determine handler adapter for the current request.
                    //根据处理器获取到处理器对应的适配器
    				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
    			    // 省略部分代码 ...
    
    				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    					return;
    				}
    
    				// Actually invoke the handler.
                    // 这里使用RequestMappingHandlerAdapter来处理请求
    				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    			// 省略部分代码 ...
    			}
                //省略部分代码 ...
    			
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    2.2、AbstractHandlerMethodAdapter的handle方法

    RequestMappingHandlerAdapter是AbstractHandlerMethodAdapter的子类,调用的是其父类的handle方法

    	@Override
    	@Nullable
    	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    			throws Exception {
    
    		return handleInternal(request, response, (HandlerMethod) handler);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    子类RequestMappingHandlerAdapter的handleInternal方法实现,具体代码如下:

    @Override
    	protected ModelAndView handleInternal(HttpServletRequest request,
    			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    		ModelAndView mav;
    		checkRequest(request);
    
    		// Execute invokeHandlerMethod in synchronized block if required.
    		if (this.synchronizeOnSession) {
    			HttpSession session = request.getSession(false);
    			if (session != null) {
    				Object mutex = WebUtils.getSessionMutex(session);
    				synchronized (mutex) {
    					mav = invokeHandlerMethod(request, response, handlerMethod);
    				}
    			}
    			else {
    				// No HttpSession available -> no mutex necessary
    				mav = invokeHandlerMethod(request, response, handlerMethod);
    			}
    		}
    		else {
    			// No synchronization on session demanded at all...
                //执行方法的调用
    			mav = invokeHandlerMethod(request, response, handlerMethod);
    		}
    
    		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
    			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
    				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
    			}
    			else {
    				prepareResponse(response);
    			}
    		}
    
    		return mav;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    接下来跟踪org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod方法

    @Nullable
    	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
    			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    	// 省略部分代码...
    		try {
    		// 省略部分代码...
    
    			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
    			if (this.argumentResolvers != null) {
    				invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    			}
    			if (this.returnValueHandlers != null) {
    				invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
    			}
    			// 省略部分代码
                
    			// 调用ServletInvocableHandlerMethod的invokeAndHandle
    			invocableMethod.invokeAndHandle(webRequest, mavContainer);
    			if (asyncManager.isConcurrentHandlingStarted()) {
    				return null;
    			}
    
    			return getModelAndView(mavContainer, modelFactory, webRequest);
    		}
    		finally {
    			webRequest.requestCompleted();
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    2.3、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);
    		}
    	   //省略部分代码 ....
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在invokeAndHandle方法中,主要干两个事情

    • invokeForRequest执行方法参数绑定、执行方法调用,获取返回值
    • this.returnValueHandlers.handleReturnValue 对controller层中的方法返回的结果进行处理

    接下来我们继续跟踪invokeForRequest方法:

    2.4、InvocableHandlerMethod#invokeForRequest

    	@Nullable
    	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);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    invokeForRequest中做了两件事情

    • 1、通过getMethodArgumentValues方法获取请求参数
    • 2、通过doInvoke使用反射进行controller层方法的调用

    然后我们接下来跟踪getMethodArgumentValues方法:

    2.5、getMethodArgumentValues方法源码

    // InvocableHandlerMethod.java
    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++) {
    	     //省略部分代码....
                
                //使用参数解析器来解析对应的参数,这里是HandlerMethodArgumentResolverComposite
    				args[i] = 
                        this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
    		//省略部分代码....
            }
    		return args;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    getMethodArgumentValues方法中的主要逻辑是:

    • 1、获取即将调用的controller层方法对应的参数,如果没有参数直接进行返回
    • 2、调用参数解析器(HandlerMethodArgumentResolverComposite)来执行参数的解析

    接下来的任务是跟踪HandlerMethodArgumentResolverComposite如果从请求中解析对应的参数出来:

    2.6 resolveArgument源码跟踪

    // HandlerMethodArgumentResolverComposite.java
    @Override
    	@Nullable
    	public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
    			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    		
            //根据调用方法来获取支持的参数解析器
    		HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
    		if (resolver == null) {
    			throw new IllegalArgumentException("Unsupported parameter type [" +
    					parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
    		}
            // 使用RequestResponseBodyMethodProcessor来解析对应的参数
    		return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    resolveArgument方法的主要作用是:

    • 1、根据对应方法和参数获取支持的方法及参数解析器,这里获取的是RequestResponseBodyMethodProcessor实例对象
    • 2、使用RequestResponseBodyMethodProcessor解析方法参数

    接下来我们继续跟踪RequestResponseBodyMethodProcessor的resolveArgument方法

    2.7、RequestResponseBodyMethodProcessor#resolveArgument

    	@Override
    	public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
    			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    
    		parameter = parameter.nestedIfOptional();
            
            // 从httpInputMessage中来读取请求体信息
    		Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
           // 省略部分代码...
    
    		return adaptArgumentIfNecessary(arg, parameter);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    resolveArgument方法方法主要部分就是调用了readWithMessageConverters方法

    2.8、readWithMessageConverters方法解析

    // RequestResponseBodyMethodProcessor.java
    @Override
    	protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
    			Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
    
    		HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
    		Assert.state(servletRequest != null, "No HttpServletRequest");
            // 创建一个HttpInputMessage对象
    		ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
    		//调用另一个重载方法
    		Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
    		if (arg == null && checkRequired(parameter)) {
    			throw new HttpMessageNotReadableException("Required request body is missing: " +
    					parameter.getExecutable().toGenericString(), inputMessage);
    		}
    		return arg;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    readWithMessageConverters方法主要做了两个事情

    • 1、基于原始请求的Request构造一个ServletServerHttpRequest对象
    • 2、调用重载的readWithMessageConverters方法来执行真正的参数绑定

    2.9、readWithMessageConverters方法解析

    // RequestResponseBodyMethodProcessor.java
    @Nullable
        protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
                                                       Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
            // 省略部分代码 ...
            Object body = NO_VALUE;
    
            AbstractMessageConverterMethodArgumentResolver.EmptyBodyCheckingHttpInputMessage message = null;
         
                message = new AbstractMessageConverterMethodArgumentResolver.EmptyBodyCheckingHttpInputMessage(inputMessage);
    
                for (HttpMessageConverter<?> converter : this.messageConverters) {
                    Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
                    GenericHttpMessageConverter<?> genericConverter =
                            (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
                    if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
                            (targetClass != null && converter.canRead(targetClass, contentType))) {
                        if (message.hasBody()) {
                            //执行所有符合条件的RequestBodyAdvice对应的beforeBodyRead方法
                            HttpInputMessage msgToUse =
                                    getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
                            //使用MappingJackson2HttpMessageConverter消息转换器来读取对应的消息
                            body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
                                    ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
                            //执行所有符合条件的RequestBodyAdvice对应的afterBodyRead方法
                            body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
                        }
                        else {
                            body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
                        }
                        break;
                    }
                }
    
            // 省略部分代码 ...
            return body;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    该方法中主要有三件事情进行处理

    • 1、调用RequestResponseBodyAdviceChain的beforeBodyRead来修改原始的HttpInputMessage对象
    • 2、调用MappingJackson2HttpMessageConverte的read方法来进行数据的读取,这里入参中HttpInputMessage对象为上一步中返回的
    • 3、调用RequestResponseBodyAdviceChain的afterBodyRead方法来修改第二步中返回的body

    我们继续来回到org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest方法中,来看下获取到参数入参后的处理方法

    2.10、invokeForRequest方法执行真正controller层调用

    	@Nullable
    	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);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    该方法主要是使用上面所讲通过MappingJackson2HttpMessageConverte从Request中绑定出来的参数对象进行controller层的方法调用

    接下来跟踪下获取到结果返回值后,如何对结果进行处理的,org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle

    2.11、invokeAndHandle返回值逻辑处理

    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
    			Object... providedArgs) throws Exception {
              // 省略部分代码...
    			this.returnValueHandlers.handleReturnValue(
    					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    		//省略部分代码...
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里我们核心关注下this.returnValueHandlers.handleReturnValue方法的执行,这个是HandlerMethodReturnValueHandlerComposite对象

    2.12、handleReturnValue源码跟踪

    //HandlerMethodReturnValueHandlerComposite#handleReturnValue
    @Override
    	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
    			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    	// 根据返回的值及返回值类型来选择符合条件的HandlerMethodReturnValueHandler对象
    		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
    		if (handler == null) {
    			throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    		}
            //使用前面获取到的实例来处理返回的结果值
    		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    上述方法逻辑很简单,主要是干两个事情

    • 1、根据返回的结果和MethodParameter对象来到对应的返回值处理器对象
    • 2、使用第一步获取到的对象对返回的值进行真正处理

    2.13、selectHandler方法解析

    //HandlerMethodReturnValueHandlerComposite.java	
    @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;
    			}
    			if (handler.supportsReturnType(returnType)) {
    				return handler;
    			}
    		}
    		return null;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    上述方法的逻辑的是依次遍历HandlerMethodReturnValueHandlerComposite中所有的HandlerMethodReturnValueHandler对象,一旦有支持的那么就会返回该处理器,遍历完后如果还是没有找到那么就返回null对象。我们这里使用的是RequestResponseBodyMethodProcessor对象,org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#supportsReturnType

    // RequestResponseBodyMethodProcessor.java
    @Override
    	public boolean supportsReturnType(MethodParameter returnType) {
    		return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
    				returnType.hasMethodAnnotation(ResponseBody.class));
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    从上面的代码可以看出来,当类层级或者方法层级上有@ResponseBody注解的时候,将会使用RequestResponseBodyMethodProcessor来进行处理

    我们来继续跟踪handleReturnValue方法

    2.14、handleReturnValue方法解析

    // RequestResponseBodyMethodProcessor.java	
    @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);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    该方法的核心的就是调用了writeWithMessageConverters方法,接下来跟踪下该方法

    2.15、writeWithMessageConverters方法源码解析

    protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
    			ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
    			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
    
    	
    		// 省略部分代码 ...
    		if (selectedMediaType != null) {
    			selectedMediaType = selectedMediaType.removeQualityValue();
    			for (HttpMessageConverter<?> converter : this.messageConverters) {
    				GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
    						(GenericHttpMessageConverter<?>) converter : null);
                    //判断当前的HttpMessageConverter是否能够写入该对象
    				if (genericConverter != null ?
    						((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
    						converter.canWrite(valueType, selectedMediaType)) {
                        // 请求体进行写入的前置处理
    					body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
    							(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
    							inputMessage, outputMessage);
    					if (body != null) {
    						Object theBody = body;
    						LogFormatUtils.traceDebug(logger, traceOn ->
    								"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
    						addContentDispositionHeader(inputMessage, outputMessage);
    						if (genericConverter != null) {
                                //使用MappingJackson2HttpMessageConverter对象进行写入
    							genericConverter.write(body, targetType, selectedMediaType, outputMessage);
    						}
    						else {
    							((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
    						}
    					}
    					else {
    						if (logger.isDebugEnabled()) {
    							logger.debug("Nothing to write: null body");
    						}
    					}
    					return;
    				}
    			}
    		}
    	// 省略部分代码 ...
    	
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    至此,我们分析完了所有整个流程的代码!

    三、源码涉及的到的重点类以及方法总结

    3.1 涉及的接口及类

    • 1、HandlerMethodArgumentResolver接口: 用来对一个request进行参数解析的接口,如我们使用@RequestBody注解的时候,会使用RequestResponseBodyMethodProcessor来进行处理参数

    • 2、RequestResponseBodyMethodProcessor:HandlerMethodArgumentResolver接口的实现类,主要是用来处理在方法参数添加了@RequestBody注解的赋值操作以及在方法上添加了@RequestBody的返回值的处理

    • 3、HttpMessageConverter接口: 用来将请求体和响应体进行转换的接口

      将请求转换为接口入参,将http处理方法的返回值转换为http响应。

    • 4、MappingJackson2HttpMessageConverter实现类:

      HttpMessageConverter接口的实现类,用来读取和写入JSON格式类型的请求

    • 5、RequestBodyAdvice: 可以对使用@RequestBody注释的参数进行修改

    • 6、ResponseBodyAdvice:对使用了@ResponseBody注释的方法或类,用来对请求进行修改

    }
    ``

    至此,我们分析完了所有整个流程的代码!

    三、源码涉及的到的重点类以及方法总结

    3.1 涉及的接口及类

    • 1、HandlerMethodArgumentResolver接口: 用来对一个request进行参数解析的接口,如我们使用@RequestBody注解的时候,会使用RequestResponseBodyMethodProcessor来进行处理参数

    • 2、RequestResponseBodyMethodProcessor:HandlerMethodArgumentResolver接口的实现类,主要是用来处理在方法参数添加了@RequestBody注解的赋值操作以及在方法上添加了@RequestBody的返回值的处理

    • 3、HttpMessageConverter接口: 用来将请求体和响应体进行转换的接口

      将请求转换为接口入参,将http处理方法的返回值转换为http响应。

    • 4、MappingJackson2HttpMessageConverter实现类:

      HttpMessageConverter接口的实现类,用来读取和写入JSON格式类型的请求

    • 5、RequestBodyAdvice: 可以对使用@RequestBody注释的参数进行修改

    • 6、ResponseBodyAdvice:对使用了@ResponseBody注释的方法或类,用来对请求进行修改
      在这里插入图片描述

  • 相关阅读:
    ARM架构
    一些常见的字符串匹配算法
    DAY-2 | 哈希表、指针与区间划分:字符种数统计问题
    烟台-青岛五日游
    Unity的配置文件在安卓路径下使用的方法
    T1级,生产环境事故—Shell脚本一键备份K8s的YAML文件
    自动驾驶仿真模型搭建
    GAN实战笔记——第三章第一个GAN模型:生成手写数字
    OpenGLES:绘制一个颜色渐变的圆
    数据结构学习系列之顺序表的两种删除方式
  • 原文地址:https://blog.csdn.net/zhangshenglu1/article/details/133981629