springboot源码分析:关于HandlerMethodReturnValueHandler的原理

Scroll Down

1、HandlerMethodReturnValueHandler的调用入口。

在RequestMappingHandlerAdapter驱动ServletInvocableHandlerMethod中经过获取请求,转化成控制器方法参数和调用控制器方法参数之后,就是处理返回值的阶段。

/**
 * Invoke the method and handle the return value through one of the
 * configured {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}.
 * @param webRequest the current request
 * @param mavContainer the ModelAndViewContainer for this request
 * @param providedArgs "given" arguments matched by type (not resolved)
 */
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
	// 执行绑定,方法调用之后得到返回值,这里的返回值需要被处理才能使用。
	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	setResponseStatus(webRequest);

	if (returnValue == null) {
		if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
			disableContentCachingIfNecessary(webRequest);
			mavContainer.setRequestHandled(true);
			return;
		}
	}
	else if (StringUtils.hasText(getResponseStatusReason())) {
		mavContainer.setRequestHandled(true);
		return;
	}
	// 将容器的状态设置为未处理完成
	mavContainer.setRequestHandled(false);
	Assert.state(this.returnValueHandlers != null, "No return value handlers");
	try {
		// 使用HandlerMethodReturnValueHandlerComposite做为代理类处理返回值。
		this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
	catch (Exception ex) {
		if (logger.isTraceEnabled()) {
			logger.trace(formatErrorForReturnValue(returnValue), ex);
		}
		throw ex;
	}
}

HandlerMethodReturnValueHandlerComposite是在RequestMappingHandlerAdapter中初始化完成的。
代码如下:

/**
 * Return the list of return value handlers to use including built-in and
 * custom handlers provided via {@link #setReturnValueHandlers}.
 */
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;
}

HandlerMethodReturnValueHandler接口方法如下:
image.png
HandlerMethodReturnValueHandlerComposite这个类使用了装饰模式,实现了HandlerMethodReturnValueHandler。
supportsReturnType方法如下:

/**
 * Whether the given {@linkplain MethodParameter method return type} is supported by any registered
 * {@link HandlerMethodReturnValueHandler}.
 */
@Override
public boolean supportsReturnType(MethodParameter returnType) {
	// 通过returnType来判断是否存在支持的ReturnValueHandler
	return getReturnValueHandler(returnType) != null;
}

@Nullable
private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
	for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
		if (handler.supportsReturnType(returnType)) {
			return handler;
		}
	}
	return null;
}

handleReturnValue方法代码如下:

/**
 * Iterate over registered {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers} and invoke the one that supports it.
 * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
 */
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
	// 筛选出符合条件的HandlerMethodReturnValueHandler
	HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
	// 如果不存在则抛出IllegalArgumentException异常
	if (handler == null) {
		throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
	}
	// 执行真正的处理返回值逻辑
	handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

// 筛选出合适的HandlerMethodReturnValueHandler
@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;
}

2、HandlerMethodReturnValueHandler的实现类的原理分析

####(1)、ModelAndViewMethodReturnValueHandler
该类用于支持返回值类型是ModelAndView的情况。
supportsReturnType方法如下:

@Override
public boolean supportsReturnType(MethodParameter returnType) {
	// 判断returnType的类型是否是ModelAndView类型及子类。
	// 这里的MethodParameter其实还是要依赖于HandlerMethod的数据。
	return ModelAndView.class.isAssignableFrom(returnType.getParameterType());
}

handleReturnValue方法如下:

@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
	// 如果return直接返回,这里其实不会出现null的情况。
	if (returnValue == null) {
		mavContainer.setRequestHandled(true);
		return;
	}

	ModelAndView mav = (ModelAndView) returnValue;
	// 如果ModelAndView的view是String
	if (mav.isReference()) {
		// 获取View名称。
		String viewName = mav.getViewName();
		// 将View的名称设置ModelAndViewContainer中。
		mavContainer.setViewName(viewName);
		if (viewName != null && isRedirectViewName(viewName)) {
			mavContainer.setRedirectModelScenario(true);
		}
	}
	else {
		View view = mav.getView();
		mavContainer.setView(view);
		if (view instanceof SmartView && ((SmartView) view).isRedirectView()) {
			mavContainer.setRedirectModelScenario(true);
		}
	}
	// 设置处理状态:HttpStatus。
	mavContainer.setStatus(mav.getStatus());
	// 将Model的数据也设置到ModelAndViewContainer中。
	mavContainer.addAllAttributes(mav.getModel());
}

####(2)、RequestResponseBodyMethodProcessor
处理当存在@ResponseBody注解标记时。
supportsReturnType方法如下:

@Override
public boolean supportsReturnType(MethodParameter returnType) {
	// 如果Controller类存在ResponseBody注解或者方法存在ResponseBody注解时处理。
	return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
				returnType.hasMethodAnnotation(ResponseBody.class));
}

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.
	// 执行参数的转化和写入到OutputStream中。
	writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

HandlerMethodReturnValueHandler的使用

功能:
对方法上标记@ReturnValue的注解自动转化成json,这里只是个例子,具体可以根据需求来改造。
(1)、首先自定义一个HandlerMethodReturnValueHandler

public class MyMethodReturnValueResolver implements HandlerMethodReturnValueHandler {

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
	// 参数的方法需要被@ReturnValue注解标记
        return returnType.hasMethodAnnotation(ReturnValue.class);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
	// 将requestHandled置为true。表示已经处理完成,不再需要被模版解析。
        mavContainer.setRequestHandled(true);
        String result = JSON.toJSONString(returnValue);
	// 获取HttpServletResponse对象。
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
        ServletServerHttpResponse servletServerHttpResponse = new ServletServerHttpResponse(response);
        
servletServerHttpResponse.getBody().write(result.getBytes());
	// 关闭并刷新流。
        servletServerHttpResponse.getBody().close();
        servletServerHttpResponse.getBody().flush();
    }
}

(2)、将MyMethodReturnValueResolver对象设置到RequestMappingHandlerAdapter中。

@PostConstruct
public void init() {
    MyMethodReturnValueResolver myMethodReturnValueResolver = new MyMethodReturnValueResolver();
    List<HandlerMethodReturnValueHandler> handlerMethodReturnValueHandlers = new ArrayList<>();
    handlerMethodReturnValueHandlers.add(myMethodReturnValueResolver);
    handlerMethodReturnValueHandlers.addAll(requestMappingHandlerAdapter.getReturnValueHandlers());
    requestMappingHandlerAdapter.setReturnValueHandlers(handlerMethodReturnValueHandlers);
}

(3)、使用:

@RequestMapping("fast")
@ReturnValue
public AmdCpu fast() {
    AmdCpu amdCpu = new AmdCpu();
    amdCpu.setType("gaoming");
    amdCpu.setName("gaoming");
    amdCpu.setNumber(1111);
    AmdMainBoard amdMainBoard = new AmdMainBoard();
    amdMainBoard.setSize(123L);
    amdCpu.setMainBoard(amdMainBoard);
    return amdCpu;
}

结果如下:

{
    "mainBoard": {
        "name": "amd main board",
        "size": 123
    },
    "name": "gaoming",
    "number": 1111,
    "type": "gaoming"
}

这里仅仅介绍了平时开发中会遇到的处理器。