1、前言
在上一篇《Spring MVC组件HandlerMethodArgumentResolver》中,分析了关于Spring MVC中参数解析器HandlerMethodArgumentResolver系列的类,这一节我们分析学习处理器方法返回值的解析器HandlerMethodReturnValueHandler系列的类。和参数解析器相比,因为返回值的相对确定性(返回值个数),所以返回值解析器的逻辑相对比较简单。
2、HandlerMethodReturnValueHandler类图
HandlerMethodReturnValueHandler用在ServletInvocableHandlerMethod(request处理器)中,主要是用来处理处理器方法执行后的返回值。主要实现了一下功能:
- 设置参数到Model;
- 设置视图View;
- 设置处理状态。如果请求已经处理完则设置ModelAndViewContainer的requestHandled为true。
在返回值处理器的家族中,其中有一个返回值解析器比较特殊,就是HandlerMethodReturnValueHandlerComposite解析器,和参数解析器中的HandlerMethodArgumentResolverComposite类功能一样,它不具体解析方法的返回值,而是可以将多个别的解析器包含在其中,解析时调用其所包含的解析器具体解析方法返回值。
在分析参数解析器的时候,我们提到了有两类的解析器:一类只能解析参数,一类既可以做参数解析器,又可以做方法返回值解析器。因此,在方法返回值处理器中,除里前面提到的可以同时处理参数和返回值的处理器外,也提供了只作为方法返回值的处理器XXXReturnValueHandler,其中XXX表示解析器处理的返回值类型。其中还定义了一个AsyncHandlerMethodReturnValueHandler接口,用来定义异步方法的返回值的解析器。
HandlerMethodReturnValueHandler接口
HandlerMethodReturnValueHandler接口有两个方法, 和参数解析器接口一样。一个用于判断是否支持该类型的判断,一个用来处理方法的返回值。
public interface HandlerMethodReturnValueHandler {
//判断是否支持该类型
boolean supportsReturnType(MethodParameter returnType);
//处理返回值
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
3、HandlerMethodReturnValueHandlerComposite类
在前面我们分析了参数解析器的HandlerMethodArgumentResolverComposite类,这里的HandlerMethodReturnValueHandlerComposite返回值解析器实现基本上一样。我们简单分析一下其中的实现逻辑:
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
protected final Log logger = LogFactory.getLog(getClass());
//定义变量,用来存储注册的真正用来处理方法返回值的解析器
private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
//获取当前类,可以使用的真正的解析器集合
public List<HandlerMethodReturnValueHandler> getHandlers() {
return Collections.unmodifiableList(this.returnValueHandlers);
}
//实现接口方法,用来判断是否支持该类型的返回值,还是通过循环处理器集合,分别判断集合中的每个解析器是否支持该返回值类型,有一个支持即返回true
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return getReturnValueHandler(returnType) != null;
}
//循环处理器集合,判断集合中的每个解析器是否支持该返回值类型,有一个支持即返回true
@Nullable
private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
//接口方法实现,处理返回值
@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);
}
//获取符合要求的解析器,需要判断是否是异步处理的解析器
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
//首先,判断是否是异步处理的方法调用
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
//如果是异步处理方法,必须是实现了AsyncHandlerMethodReturnValueHandler异步解析器的实现类才可以使用
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
//判断是否支持该返回值类型,并返回处理器实例
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
//是否异步处理的方法判断
private boolean isAsyncReturnValue(@Nullable Object value, MethodParameter returnType) {
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (handler instanceof AsyncHandlerMethodReturnValueHandler &&
((AsyncHandlerMethodReturnValueHandler) handler).isAsyncReturnValue(value, returnType)) {
return true;
}
}
return false;
}
//添加支持的解析器
public HandlerMethodReturnValueHandlerComposite addHandler(HandlerMethodReturnValueHandler handler) {
this.returnValueHandlers.add(handler);
return this;
}
//添加支持的解析器
public HandlerMethodReturnValueHandlerComposite addHandlers(
@Nullable List<? extends HandlerMethodReturnValueHandler> handlers) {
if (handlers != null) {
this.returnValueHandlers.addAll(handlers);
}
return this;
}
}
4、ViewNameMethodReturnValueHandler类
在HandlerMethodReturnValueHandler家族中,有很多种类型的返回值解析器,这里我们通过分析ViewNameMethodReturnValueHandler类,了解返回值解析器的实现逻辑。ViewNameMethodReturnValueHandler类主要是用来处理视图view是字符串或者void类型的解析器,实现比较简单,我们直接看具体实现:
public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
//判断是否是Redirect类型的表达式
@Nullable
private String[] redirectPatterns;
//省略 redirectPatterns属性的get/set方法
//接口方法实现,判断返回值是否是void类型或字符串类型,CharSequence接口是所有字符串类型的抽象接口
@Override
public boolean supportsReturnType(MethodParameter returnType) {
Class<?> paramType = returnType.getParameterType();
return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
}
//接口方法实现,处理符合要求的返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//判断如果是字符串类型的,就转换成String 类型,并设置到ModelAndViewContainer的view属性中
if (returnValue instanceof CharSequence) {
String viewName = returnValue.toString();
//设置到ModelAndViewContainer的view属性中
mavContainer.setViewName(viewName);
//判断是否是Redirect类型
if (isRedirectViewName(viewName)) {
//如果是Redirect类型,设置ModelAndViewContainer中的对应标志
mavContainer.setRedirectModelScenario(true);
}
}
else if (returnValue != null) {
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
//判断是否是Redirect类型
protected boolean isRedirectViewName(String viewName) {
return (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName) || viewName.startsWith("redirect:"));
}
}
5、总结
因为有了前面学习参数解析器的经验,分析返回值解析器相对比较简单,因为一些思路是类似的。HandlerMethodReturnValueHandler家族中的其他类这里不再一个个进行分析,感兴趣的童鞋,可以直接查看源码。关于异步处理相关知识,后续学习过程中再整理记录。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68793.html