SpringMVC源码:参数解析、方法调用与返回值处理

  • Post author:
  • Post category:其他


参考资料:


《SpringMVC源码解析系列》


《SpringMVC源码分析》


《Spring MVC源码》

写在开头:本文为个人学习笔记,内容比较随意,夹杂个人理解,如有错误,欢迎指正。

前文:


《SpringMVC源码:DispatcherServlet初始化流程》


《SpringMVC源码:HandlerMapping加载1》


《SpringMVC源码:HandlerMapping加载2》


《SpringMVC源码:getHandler、getHandlerAdapter过程》

前文我们已经介绍了,doDispatch方法过程中的handler查找、适配器查找以及拦截器preHandle方法的执行,本文我们会继续介绍方法的调用。

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 {
            //检查是否为Multipart请求,如果是则HttpServletRequest转换为MultipartHttpServletRequest
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);
            //1.根据request信息寻找对应的Handler
            //并返回mappedHeadler,它是一个执行链,包含拦截器和自定义controller
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                //没有找到Handler则通过response反馈错误信息
                noHandlerFound(processedRequest, response);
                return;
            }
            // 2.根据当前的handler寻找对应的HandlerAdapter
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            // 当前handler处理last-modified
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
            //3.mappedHandler调用拦截器的preHandler方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            // 4.HandlerAdapter调用自定义Controller中的方法并返回ModelAndView
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            //5.视图解析,为request请求找到视图
            applyDefaultViewName(processedRequest, mv);
            //6.调用拦截器的postHandle方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
}

在这里插入图片描述


目录


一、handle


1、AbstractHandlerMethodAdapter#handle


2、RequestMappingHandlerAdapter#handleInternal


3、RequestMappingHandlerAdapter#invokeHandlerMethod


4、ServletInvocableHandlerMethod#invokeAndHandle


InvocableHandlerMethod#invokeForRequest


5、RequestMappingHandlerAdapter#getModelAndView


二、@RequestBody与@ResponseBody


1、接口转换


2、参数解析


2.1、查找解析器


2.2、解析过程


3、返回值处理


3.1、选择处理器


3.2、处理过程


补充


解析器和转换器在什么时候注册添加的


一、handle

1、AbstractHandlerMethodAdapter#handle

这里以AbstractHandlerMethodAdapter类为例,可以看到内部实际上是调用了handleInternal方法,而这个方法实际上是由子类RequestMappingHandlerAdapter实现的。(注意下这里的返回值为ModelAndView)

	@Override
	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}

2、RequestMappingHandlerAdapter#handleInternal

该方法主要进行了对请求request的相关校验、解析、转换、执行相关的handler的invokeHandlerMethod 并返回对应的数据视图对象。

	@Override
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		ModelAndView mav;
        //如果设置supportMethods、requireSession属性需要对其进行校验
        //如果处理的请求方式不是supportMethods集合支持的抛出异常
        //或者requireSession为true但是request不包含session同样抛出异常
		checkRequest(request);


        // 针对线程不安全的session 提供两种方式 一种是同步 从而保证该会话的用户串行执行请求
        // 一种是非同步处理请求 不管同步与否最终调用核心方法invokeHandlerMethod 调用HandlerMethod
		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;
	}

3、RequestMappingHandlerAdapter#invokeHandlerMethod

这一步中将HandlerMethod被封装ServletInvocableHandlerMethod,包裹上方法执行需要的信息并调用invokeAndHandle方法执行,最后通过getModelAndView获取视图。

	protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        //先将请求响应对象包装成ServletWebRequest
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		try {
            
            //获取该方法的所有使用@InitBinder注解修饰的方法
            //包装成WebDataBinderFactory 在handlerMethod执行前调用(包含类作用范围的和全局作用范围的)
			WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            //获取该方法的所有使用@ModelAttribute注解修饰的方法 包装成ModelFactory(包含类作用范围的和全局作用范围的)
			ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

            //将HandlerMethod方法包装成ServletInvocableHandlerMethod(该对象是InvocableHandlerMethod子类)
            //设置相关的组件 比如设置参数解析组件argumentResolvers和返回结果处理组件returnValueHandlers
            //绑定组件binderFactory和parameterNameDiscoverer
			ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
			invocableMethod.setDataBinderFactory(binderFactory);
			invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

            //创建数据模型和视图的容器对象 见名知义其包含我们所常见的数据和视图对象
			ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            //对于重定向相关的参数保存需要依赖flashMap对象,如果一个请求是重定向请求 则input_flash_map保存重定向入参
            //如果一个请求需要进行重定向 则参数会存放到output_flash_map中
			mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            //调用@ModelAttribute注解修饰的方法将对应的属性存放到mavContainer 的model中
			modelFactory.initModel(webRequest, mavContainer, invocableMethod);
			mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
            //异步请求处理
			AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
			asyncWebRequest.setTimeout(this.asyncRequestTimeout);

			WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
			asyncManager.setTaskExecutor(this.taskExecutor);
			asyncManager.setAsyncWebRequest(asyncWebRequest);
			asyncManager.registerCallableInterceptors(this.callableInterceptors);
			asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

			if (asyncManager.hasConcurrentResult()) {
				Object result = asyncManager.getConcurrentResult();
				mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
				asyncManager.clearConcurrentResult();
				if (logger.isDebugEnabled()) {
					logger.debug("Found concurrent result value [" + result + "]");
				}
				invocableMethod = invocableMethod.wrapConcurrentResult(result);
			}

            //通过反射执行相关的handlerMethod 涉及参数解析,返回值的处理、
            //invocableMethod已经包含了进行参数解析和返回值处理的组件对象
			invocableMethod.invokeAndHandle(webRequest, mavContainer);
			if (asyncManager.isConcurrentHandlingStarted()) {
				return null;
			}

            //主要处理sessionAttribute 以及对model中的属性进行属性编辑器的转换处理@InitBinder
            //对于view对象进行逻辑视图到物理视图的转换以及重定向参数的设置
			return getModelAndView(mavContainer, modelFactory, webRequest);
		}
		finally {
			webRequest.requestCompleted();
		}
	}

4、ServletInvocableHandlerMethod#invokeAndHandle

首先调用invokeForRequest进行参数解析与方法调用,得到返回值后将其封装入mavContainer中。

	public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        // 请求处理
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        // 返回值处理
        this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}

InvocableHandlerMethod#invokeForRequest

invokeForRequest方法首先解析参数,然后反射执行方法。

	public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        //调用getMethodArgumentValues进行参数解析
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        //调用doInvoke方法反射执行handler处理器
		Object returnValue = doInvoke(args);
		return returnValue;
	}
	protected Object doInvoke(Object... args) throws Exception {
		ReflectionUtils.makeAccessible(getBridgedMethod());
		return getBridgedMethod().invoke(getBean(), args);
	}

5、RequestMappingHandlerAdapter#getModelAndView

从mavContainer取出结果包装成ModelAndView并返回给前端控制器,整个handler处理器的调用完成,后续进入视图处理阶段。

	private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

		modelFactory.updateModel(webRequest, mavContainer);
		if (mavContainer.isRequestHandled()) {
			return null;
		}
        //从mavContainer中取出model 
		ModelMap model = mavContainer.getModel();
        //根据取出的model创建视图对象
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
		if (!mavContainer.isViewReference()) {
			mav.setView((View) mavContainer.getView());
		}
        //处理redirect请求
		if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
		}
		return mav;
	}

二、@RequestBody与@ResponseBody

以下内容参考自

《Spring MVC源码(三) —– @RequestBody和@ResponseBody原理解析》

在上文中我们介绍了invokeAndHandle方法,其中的两个步骤分别为参数解析与返回值处理,这一节我们结合两个常用注解@RequestBody与@ResponseBody来进行这部分内容的讲解。

首先来看个样例,第一个requestBody请求,使用@RequestBody将HTTP请求体转换成String类型,第二个responseBody请求,将Map对象转换成json格式输出到HTTP响应中。

@RequestMapping("/requestBody")
public void requestBody(@RequestBody String body, Writer writer) throws IOException{
    writer.write(body);
}

@RequestMapping(value="/responseBody", produces="application/json")
@ResponseBody
public Map<String, Object> responseBody(){
    Map<String, Object> retMap = new HashMap<>();
    retMap.put("param1", "abc");
    return retMap;
}

这两个注解都实现了HTTP报文信息同Controller方法中对象的转换,下面我们就来进行原理分析。

1、接口转换



SpringMVC中为了实现HTTP消息体和参数及返回值进行转换,所有转换类都实现了HttpMessageConverter接口,该接口定义了5个方法,用于将HTTP请求报文转换为java对象,以及将java对象转换为HTTP响应报文。

public interface HttpMessageConverter<T> {

    // 当前转换器是否能将HTTP报文转换为对象类型
    boolean canRead(Class<?> clazz, MediaType mediaType);

    // 当前转换器是否能将对象类型转换为HTTP报文
    boolean canWrite(Class<?> clazz, MediaType mediaType);

    // 转换器能支持的HTTP媒体类型
    List<MediaType> getSupportedMediaTypes();

    // 转换HTTP报文为特定类型
    T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException;

    // 将特定类型对象转换为HTTP报文
    void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException;

}



对应到SpringMVC的Controller方法,read方法即是读取HTTP请求转换为参数对象,write方法即是将返回值对象转换为HTTP响应报文。SpringMVC定义了两个接口来操作这两个过程:参数解析器HandlerMethodArgumentResolver和返回值处理器HandlerMethodReturnValueHandler。

// 参数解析器接口
public interface HandlerMethodArgumentResolver {

    // 解析器是否支持方法参数
    boolean supportsParameter(MethodParameter parameter);

    // 解析HTTP报文中对应的方法参数
    Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;

}

// 返回值处理器接口
public interface HandlerMethodReturnValueHandler {

    // 处理器是否支持返回值类型
    boolean supportsReturnType(MethodParameter returnType);

    // 将返回值解析为HTTP响应报文
    void handleReturnValue(Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;

}

参数解析器和返回值处理器在底层处理时,都是通过HttpMessageConverter进行转换。流程如下:



RequestResponseBodyMethodProcessor类实现了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler两个接口,@RequestBody和@ResponseBody这两个注解的解析均由该类来实现。

2、参数解析

在上文中我们介绍了getMethodArgumentValues方法实现了参数解析但并未深入解析,这里我们进行下源码分析

	private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		MethodParameter[] parameters = getMethodParameters();
		Object[] args = new Object[parameters.length];
        // 遍历所有参数,逐个解析
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			args[i] = resolveProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}    
            // 通过supportsParameter方法寻找参数合适的解析器
			if (this.argumentResolvers.supportsParameter(parameter)) {
				try {
					args[i] = this.argumentResolvers.resolveArgument(
							parameter, mavContainer, request, this.dataBinderFactory);
					continue;
				}
				catch (Exception ex) {
					if (logger.isDebugEnabled()) {
						logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
					}
					throw ex;
				}
			}
			if (args[i] == null) {
				throw new IllegalStateException("Could not resolve method parameter at index " +
						parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
						": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
			}
		}
		return args;
	}

2.1、查找解析器

HandlerMethodArgumentResolverComposite类实现了supportsParameter方法,后续调用argumentResolverCache即参数解析器

	private final List<HandlerMethodArgumentResolver> argumentResolvers =
			new LinkedList<HandlerMethodArgumentResolver>();

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return getArgumentResolver(parameter) != null;
	}

	private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
			for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
				if (resolver.supportsParameter(parameter)) {
					result = resolver;
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}

我们直接进入HandlerMethodArgumentResolver接口的实现类,也正是我们上问提到的RequestResponseBodyMethodProcessor来看看

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

可以看到这里实际上就是判断方法上是否有@RequestBody,这就印证了我们所说的@RequestBody由RequestResponseBodyMethodProcessor来实现解析。

2.2、解析过程

已经通过supportsParameter确定了由RequestResponseBodyMethodProcessor类来进行解析,下面再看如何解析,于是我们跟着源码进入resolveArgument方法。

	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, 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.");
		}
		return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
	}

其核心内容为通过readWithMessageConverters读取HTTP的请求体内容,而该方法由AbstractMessageConverterMethodArgumentResolver负责实现。

    // RequestResponseBodyMethodProcessor.java
	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

		parameter = parameter.nestedIfOptional();
        // 读取HTTP报文
		Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
		String name = Conventions.getVariableNameForParameter(parameter);

		WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
		if (arg != null) {
			validateIfApplicable(binder, parameter);
			if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
				throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
			}
		}
		mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());

		return adaptArgumentIfNecessary(arg, parameter);
	}

	@Override
	protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
			Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

		HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
		ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
        //调用AbstractMessageConverterMethodArgumentResolver中的实现
		Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
		if (arg == null) {
			if (checkRequired(parameter)) {
				throw new HttpMessageNotReadableException("Required request body is missing: " +
						parameter.getMethod().toGenericString());
			}
		}
		return arg;
	}



这里的关键部分即是遍历所有的HttpMessageConverter,通过canRead方法判断转换器是否支持对参数的转换,然后执行read方法完成转换。

protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
        Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

    ....

    try {
        inputMessage = new EmptyBodyCheckingHttpInputMessage(inputMessage);

        for (HttpMessageConverter<?> converter : this.messageConverters) {
            Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
            ....
            // 判断转换器是否支持参数类型
            if (converter.canRead(targetClass, contentType)) {
                if (inputMessage.getBody() != null) {
                    inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
                    // read方法执行HTTP报文到参数的转换
                    body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
                    body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
                }
                else {
                    body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
                }
                break;
            }
            ...
        }
    }
    catch (IOException ex) {
        throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
    }

    ....

    return body;
}

3、返回值处理

完成Controller方法的调用后,在ServletInvocableHandlerMethod的invokeAndHandle中,使用返回值处理器对返回值进行转换。

这里的returnValueHandlers也是HandlerMethodReturnValueHandler的集合体HandlerMethodReturnValueHandlerComposite

	public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
        // 请求处理
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        // 返回值处理
        this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}

3.1、选择处理器



handleReturnValue首先会通过selectHandler找出支持处理当前返回值的处理器,然后再调用该处理器的handleReturnValue方法进行真正的处理。

    //HandlerMethodReturnValueHandlerComposite.java
	@Override
	public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        // 选择合适的HandlerMethodReturnValueHandler,如果没有用@ResposeBody注解和用了注解其返回值处理器肯定不同
		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		if (handler == null) {
			throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
		}
        // 执行返回值处理
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}



而selectHandler方法遍历所有HandlerMethodReturnValueHandler,调用其supportsReturnType方法选择合适的HandlerMethodReturnValueHandler,然后调用其handleReturnValue方法完成处理。

    //HandlerMethodReturnValueHandlerComposite.java
	private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
		boolean isAsyncValue = isAsyncReturnValue(value, returnType);
		for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
			if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
				continue;
			}
            // 判断当前的HandlerMethodReturnValueHandler是否支持处理返回值
			if (handler.supportsReturnType(returnType)) {
				return handler;
			}
		}
		return null;
	}

RequestResponseBodyMethodProcessor要求方法上有@ResponseBody注解或者方法所在的Controller类上有@ResponseBody的注解。这就是常常用@RestController注解代替@Controller注解的原因,因为@RestController注解自带@ResponseBody。

	@Override
	public boolean supportsReturnType(MethodParameter returnType) {
		return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
				returnType.hasMethodAnnotation(ResponseBody.class));
	}

3.2、处理过程

handleReturnValue方法实际也是调用HttpMessageConverter来完成转换处理。

    //RequestResponseBodyMethodProcessor.java
	@Override
	public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
        
        // 设置该请求的返回值直接通过response返回,无视图内容
		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

        // 调用HttpMessageConverter执行
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

因为使用了@ResponseBody已经将返回值通过response的消息体进行了回传,因此这里不再需要视图了,所以设置了setRequestHandled(true)。

    // ModelAndViewContainer.java
	/**
	 * Whether the request has been handled fully within the handler, e.g.
	 * {@code @ResponseBody} method, and therefore view resolution is not
	 * necessary. This flag can also be set when controller methods declare an
	 * argument of type {@code ServletResponse} or {@code OutputStream}).
	 * <p>The default value is {@code false}.
	 */
	public void setRequestHandled(boolean requestHandled) {
		this.requestHandled = requestHandled;
	}

AbstractMessageConverterMethodProcessor使用canWrite方法选择合适的HttpMessageConverter,然后调用write方法完成转换。

//AbstractMessageConverterMethodProcessor.java
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
        ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
        throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

    ....

    if (selectedMediaType != null) {
        selectedMediaType = selectedMediaType.removeQualityValue();
        for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
            // 判断是否支持返回值类型,返回值类型很有可能不同,如String,Map,List等
            if (messageConverter.canWrite(valueType, selectedMediaType)) {
                outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
                        (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
                        inputMessage, outputMessage);
                if (outputValue != null) {
                    addContentDispositionHeader(inputMessage, outputMessage);
                    // 执行返回值转换
                    ((HttpMessageConverter) messageConverter).write(outputValue, selectedMediaType, outputMessage);
                    ...
                }
                return;
            }
        }
    }
    ....
}

补充

解析器和转换器在什么时候注册添加的

上文中提到的解析器和转换器都是在适配器初始化的时候添加的。

    //RequestMappingHandlerAdapter.java
	public RequestMappingHandlerAdapter() {
		StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
		stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316

		this.messageConverters = new ArrayList<HttpMessageConverter<?>>(4);
		this.messageConverters.add(new ByteArrayHttpMessageConverter());
		this.messageConverters.add(stringHttpMessageConverter);
		this.messageConverters.add(new SourceHttpMessageConverter<Source>());
		this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
	}

	@Override
	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);
		}
	}



版权声明:本文为wzngzaixiaomantou原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。