公众号,欢迎关注
HandlerMethodArgumentResolver
是一个策略接口,用来将方法的参数解析为参数的值,HandlerMethodArgumentResolver
有很多的实现类,比如
RequestParamMethodArgumentResolver
RequestHeaderMethodArgumentResolver
PathVariableMethodArgumentResolver
MatrixVariableMethodArgumentResolver
- … 还有很多,可以通过查看源代码查看
还有一个很特殊的实现 HandlerMethodArgumentResolverComposite
,HandlerMethodArgumentResolverComposite
实现了 HandlerMethodArgumentResolver
接口,但却没有实现具体的参数解析策略,而是将所有的具体策略都组合到了 HandlerMethodArgumentResolverComposite
中
HandlerMethodArgumentResolverComposite
是一个典型的组合模式
的实现,从类的名称也能看出一二
这样实现有什么好处呢?
组合模式有三个好处
- 去除重复代码
- 统一客户端的代码调用
- 支持对象树的处理(《重构到模式》 7.5 节有一个完美的例子)
在我看来,这里组要是体现了第二个好处,就是统一客户端的代码调用,客户只要通过与 HandlerMethodArgumentResolverComposite
进行交互即可,不需要了解具体的策略类型,对策略的选择交给 HandlerMethodArgumentResolverComposite
类进行处理
HandlerMethodArgumentResolverComposite
将客户端与具体的策略实现进行了隔离,通过 HandlerMethodArgumentResolverComposite
可以对具体的策略进行扩展而客户端无感知,也是开闭原则(OCP)的一个体现
从源码中也可以看到,几乎所有使用 HandlerMethodArgumentResolver
的地方都是实例化的 HandlerMethodArgumentResolverComposite
对象,然后将其他需要用到的具体策略添加到 HandlerMethodArgumentResolverComposite
的对象实例中
还有其他地方也用了一模一样的实现方式,例如
HandlerMethodReturnValueHandlerComposite
实现了HandlerMethodReturnValueHandler
HandlerExceptionResolverComposite
实现了HandlerExceptionResolver
WebMvcConfigurerComposite
实现了WebMvcConfigurer
实现模式也比较简单,composite 对象遍历具体的策略,调用策略接口提供 support 方法,support 方法返回自己是否支持当前的处理,如果支持则调用策略方法进行处理,如果不支持则继续向后遍历
下面便是一段典型的实现
/**
* Iterate over registered
* {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers} and
* invoke the one that supports it.
* @throws IllegalStateException if no suitable
* {@link HandlerMethodArgumentResolver} is found.
*/
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable 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);
}
/**
* Find a registered {@link HandlerMethodArgumentResolver} that supports
* the given method parameter.
*/
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
工作中有类似的需求我们可以进行借鉴