文章目录

  • 处理返回结果
  • HandlerMethodReturnValueHandler
  • RequestResponseBodyMethodProcessor的supports方法
  • RequestResponseBodyMethodProcessor的resolveArgument方法(解析请求参数)
  • readWithMessageConverters
  • RequestResponseBodyMethodProcessor的handleReturnValue方法(解析返回参数)
  • writeWithMessageConverters跟上面差不多


处理返回结果

前面说到,通过反射调用方法返回参数,参数都是使用Object接收的:

springmvc源码解析(四),@ResponseBody返回json_List

springmvc源码解析(四),@ResponseBody返回json_请求参数_02

HandlerMethodReturnValueHandler

对于返回参数的处理,跟请求参数差不多,返回参数的处理器都实现了HandlerMethodReturnValueHandler 接口,通过supportsReturnType来进行适配,handleReturnValue方法进行处理.

public interface HandlerMethodReturnValueHandler {

	boolean supportsReturnType(MethodParameter returnType);


	void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;

}

springmvc源码解析(四),@ResponseBody返回json_List_03


现在使用的比较多的就是通过注解@ResponseBody返回json,对于json的返回,springmvc是RequestResponseBodyMethodProcessor类来对返回参数进行处理的.这个类叫RequestResponse,就是表示如果请求参数也是json也是根据这个类来进行处理的.

springmvc源码解析(四),@ResponseBody返回json_List_04


我们先看看RequestResponseBodyMethodProcessor的类图:

springmvc源码解析(四),@ResponseBody返回json_List_05

RequestResponseBodyMethodProcessor的supports方法

supports方法就是判断是否有RequestBody,ResponseBody注解

springmvc源码解析(四),@ResponseBody返回json_请求参数_06

RequestResponseBodyMethodProcessor的resolveArgument方法(解析请求参数)

@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		//判断入参是不是Optional类型,是则返回嵌套类型
		parameter = parameter.nestedIfOptional();
		//读取入参(主要)
		Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
		//获取参数类型的短名称
		String name = Conventions.getVariableNameForParameter(parameter);

		//数据绑定器
		WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
		if (arg != null) {
		  //判断是否使用了validate注解
			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());

		//处理Optional类型入参的情况后返回
		return adaptArgumentIfNecessary(arg, parameter);
	}

readWithMessageConverters

@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);
// 主要
		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;
	}


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

		MediaType contentType;
		boolean noContentType = false;
		try {
			contentType = inputMessage.getHeaders().getContentType();
		}
		catch (InvalidMediaTypeException ex) {
			throw new HttpMediaTypeNotSupportedException(ex.getMessage());
		}
		if (contentType == null) {
			noContentType = true;
			contentType = MediaType.APPLICATION_OCTET_STREAM;
		}

		// 获取入参类
		Class<?> contextClass = (parameter != null ? parameter.getContainingClass() : null);
		// 获取入参的类型
		Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
		if (targetClass == null) {
			ResolvableType resolvableType = (parameter != null ?
					ResolvableType.forMethodParameter(parameter) : ResolvableType.forType(targetType));
			targetClass = (Class<T>) resolvableType.resolve();
		}

		HttpMethod httpMethod = ((HttpRequest) inputMessage).getMethod();
		Object body = NO_VALUE;

		try {
			inputMessage = new EmptyBodyCheckingHttpInputMessage(inputMessage);

			for (HttpMessageConverter<?> converter : this.messageConverters) {
				Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
				if (converter instanceof GenericHttpMessageConverter) {
					GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
					if (genericConverter.canRead(targetType, contextClass, contentType)) {
						if (logger.isDebugEnabled()) {
							logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
						}
						if (inputMessage.getBody() != null) {
						  //循环调用ControllerAdvice切面
							inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
							//调用转换器的read方法
							body = genericConverter.read(targetType, contextClass, inputMessage);
							//循环调用ControllerAdvice切面
							body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
						}
						else {
							body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
						}
						break;
					}
				}
				else if (targetClass != null) {
					if (converter.canRead(targetClass, contentType)) {
						if (logger.isDebugEnabled()) {
							logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
						}
						if (inputMessage.getBody() != null) {
							inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
							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);
		}

		if (body == NO_VALUE) {
			if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
					(noContentType && inputMessage.getBody() == null)) {
				return null;
			}
			throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
		}

		return body;
	}

调用转换器的read方法,就读取到对应的对象了,转换器,一般使用默认的MappingJackson2HttpMessageConverter转换器就够了,具体的转换可以自己点到转换器里面去看,也比较简单了;

springmvc源码解析(四),@ResponseBody返回json_请求参数_07


springmvc源码解析(四),@ResponseBody返回json_List_08


springmvc源码解析(四),@ResponseBody返回json_ci_09

RequestResponseBodyMethodProcessor的handleReturnValue方法(解析返回参数)

@Override
	public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		//视图是否需要解析,如果是true就不需要解析
		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);
	}

writeWithMessageConverters跟上面差不多

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

		Object outputValue;
		Class<?> valueType;
		Type declaredType;

		// 是不是CharSequence类型
		if (value instanceof CharSequence) {
			outputValue = value.toString();
			valueType = String.class;
			declaredType = String.class;
		}
		else {
			//处理
			outputValue = value;
			//获取返回值类型
			valueType = getReturnValueType(outputValue, returnType);
			//获取目标类型,包括泛型
			declaredType = getGenericType(returnType);
		}

		//获取对应的request
		HttpServletRequest request = inputMessage.getServletRequest();
		//获取允许的类型
		List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
		//获取可生产的类型
		List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);

		if (outputValue != null && producibleMediaTypes.isEmpty()) {
			throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
		}

		//要使用的媒体类型
		Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
		//遍历
		for (MediaType requestedType : requestedMediaTypes) {
			for (MediaType producibleType : producibleMediaTypes) {
				if (requestedType.isCompatibleWith(producibleType)) {
					compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
				}
			}
		}
		if (compatibleMediaTypes.isEmpty()) {
			if (outputValue != null) {
				throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
			}
			return;
		}

		List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
		//排序
		MediaType.sortBySpecificityAndQuality(mediaTypes);

		MediaType selectedMediaType = null;
		//找到对应的媒体类型
		for (MediaType mediaType : mediaTypes) {
			if (mediaType.isConcrete()) {
				selectedMediaType = mediaType;
				break;
			}
			else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
				selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
				break;
			}
		}

		if (selectedMediaType != null) {
			selectedMediaType = selectedMediaType.removeQualityValue();
			//遍历消息转换器
			for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
				if (messageConverter instanceof GenericHttpMessageConverter) {
					//判断消息转换器能否写
					if (((GenericHttpMessageConverter) messageConverter).canWrite(
							declaredType, valueType, selectedMediaType)) {
						//循环调用ControllerAdvice切面
						outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
								(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
								inputMessage, outputMessage);
						if (outputValue != null) {
							addContentDispositionHeader(inputMessage, outputMessage);
							//开始写
							((GenericHttpMessageConverter) messageConverter).write(
									outputValue, declaredType, selectedMediaType, outputMessage);
							if (logger.isDebugEnabled()) {
								logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
										"\" using [" + messageConverter + "]");
							}
						}
						return;
					}
				}
				else 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);
						if (logger.isDebugEnabled()) {
							logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
									"\" using [" + messageConverter + "]");
						}
					}
					return;
				}
			}
		}

		if (outputValue != null) {
			throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
		}
	}

也是在抽象类里面实现了writeInternal方法: