书接上文SpringBoot统一修改API返回值的两种方式中自定义HandlerMethodReturnValueHandler的内容,最后说道getDefaultReturnValueHandlers方法中添加了很多处理返回值的处理器,那这些处理器是如何生效的呢?
HandlerMethodReturnValueHandler在处理返回值时时如何使用适配器模式
通过分析DispatchServelet的doDispatch方法中的内容可以机进行追溯,
主要就行进行了各种适配器的选择
代码语言:txt复制 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
可以看到HandlerAdapter中的具体实现类中与我们比较相关的还是AbstractHandlerMethodAdapter,但是进一步可以发现RequestMappingHandlerAdapter是继承自AbstractHandlerMethodAdapter且实现了相应功能
那最后是如何选择到我们的自定义HandlerMethodReturnValueHandler的内容的呢
DispatchServelet中获取到了HandlerAdapter 之后即开始执行hanle方法
通过追踪handle方法到RequestMappingHandlerAdapter#invokeHandlerMethod
继而追踪到
代码语言:txt复制 @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);
}
最后通过适配器模式选择了排在第一个的我们的自定义的HandlerMethodReturnValueHandler的方法
选择适配器的方法即为通用的适配器模式实现方式,
代码语言:txt复制 @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;
}
通过将this.returnValueHandlers的第一个设置为自定义方法,即选中我们自定义的方法后就直接返回,不再进行后续方法的选择。
适配器模式
在Spring中还有很多其他使用适配器的地方,通过这种方法能够较好的选择合适的处理方法,也能够方便我们进行自定义扩展
当我看到适配器模式时,我自然而然的想到了策略模式,那么适配器模式和策略模式简化if判断到底有什么不同呢?
从我个人的理解而言,策略模式首先需要去判断你属于某个策略,然后去执行相应的操作。而适配器模式则是内部判断你是否能够适配当前操作,然后再去执行
从更加规范的角度理解
策略模式中 Context 是要接收 Strategy 类,而所有的策略也是需要实现 Strategy 类,大家都需要共同遵守 Strategy 类的约定。
适配器模式模式中 MediaAdapter 没有这层约定,第三方的 AdvancedMediaPlayer 压根就不管你那些什么约定,只管自己的输出。MediaAdapter 对接完 AdvancedMediaPlayer 后输出统一的接口让外部访问即可。