组合模式
组合(Composite)是指使用组合和继承关系将聚合体及其组成元素分解成树状结构,以便客户端在不需要区分聚合体或组成元素类型的情况下使用统一的接口操作它们
Spring MVC 中解析参数时使用组合模式
类图展示:
解析参数接口HandlerMethodArgumentResolver
代码:
public interface HandlerMethodArgumentResolver {
/**
* 用于判断是否可以解析传入的参数
*/
boolean supportsParameter(MethodParameter parameter);
/**
* 用于实际解析参数
*/
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
可以看出该接口定义了两个方法,一个判断是否可以解析参数,另一个就是实际解析参数的方法.
HandlerMethodArgumentResolver
接口的继承结构为:
上面继承结构看出有一个类HandlerMethodArgumentResolverComposite
比较特殊
再看组合类HandlerMethodArgumentResolverComposite
代码:
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
/**参数解析器集合*/
private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList<>();
private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
new ConcurrentHashMap<>(256);
/**
* 添加解析器
*/
public HandlerMethodArgumentResolverComposite addResolver(HandlerMethodArgumentResolver resolver) {
this.argumentResolvers.add(resolver);
return this;
}
/**
* 添加多个解析器
*/
public HandlerMethodArgumentResolverComposite addResolvers(
@Nullable HandlerMethodArgumentResolver... resolvers) {
if (resolvers != null) {
Collections.addAll(this.argumentResolvers, resolvers);
}
return this;
}
/**
* 添加解析器集合
*/
public HandlerMethodArgumentResolverComposite addResolvers(
@Nullable List<? extends HandlerMethodArgumentResolver> resolvers) {
if (resolvers != null) {
this.argumentResolvers.addAll(resolvers);
}
return this;
}
/**
* 返回一个只读的HandlerMethodArgumentResolver集合,或者空集合
*/
public List<HandlerMethodArgumentResolver> getResolvers() {
return Collections.unmodifiableList(this.argumentResolvers);
}
/**
* 清空解析器集合
* @since 4.3
*/
public void clear() {
this.argumentResolvers.clear();
}
/**
* 判断参数解析器是否能解析方法参数
*/
@Override
public boolean supportsParameter(MethodParameter parameter) {
return getArgumentResolver(parameter) != null;
}
/**
* 遍历注册的解析器集合,找到解析参数的解析器解析参数
*/
@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);
}
/**查找参数解析器
*/
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
}
再看具体的解析器代码,以RequestParamMapMethodArgumentResolver为
例:
public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
return (requestParam != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
!StringUtils.hasText(requestParam.name()));
}
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
if (MultiValueMap.class.isAssignableFrom(parameter.getParameterType())) {
// MultiValueMap
Class<?> valueType = resolvableType.as(MultiValueMap.class).getGeneric(1).resolve();
if (valueType == MultipartFile.class) {
MultipartRequest multipartRequest = MultipartResolutionDelegate.resolveMultipartRequest(webRequest);
return (multipartRequest != null ? multipartRequest.getMultiFileMap() : new LinkedMultiValueMap<>(0));
}
else if (valueType == Part.class) {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
if (servletRequest != null && MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
Collection<Part> parts = servletRequest.getParts();
LinkedMultiValueMap<String, Part> result = new LinkedMultiValueMap<>(parts.size());
for (Part part : parts) {
result.add(part.getName(), part);
}
return result;
}
return new LinkedMultiValueMap<>(0);
}
else {
Map<String, String[]> parameterMap = webRequest.getParameterMap();
MultiValueMap<String, String> result = new LinkedMultiValueMap<>(parameterMap.size());
parameterMap.forEach((key, values) -> {
for (String value : values) {
result.add(key, value);
}
});
return result;
}
}
else {
// Regular Map
Class<?> valueType = resolvableType.asMap().getGeneric(1).resolve();
if (valueType == MultipartFile.class) {
MultipartRequest multipartRequest = MultipartResolutionDelegate.resolveMultipartRequest(webRequest);
return (multipartRequest != null ? multipartRequest.getFileMap() : new LinkedHashMap<>(0));
}
else if (valueType == Part.class) {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
if (servletRequest != null && MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
Collection<Part> parts = servletRequest.getParts();
LinkedHashMap<String, Part> result = new LinkedHashMap<>(parts.size());
for (Part part : parts) {
if (!result.containsKey(part.getName())) {
result.put(part.getName(), part);
}
}
return result;
}
return new LinkedHashMap<>(0);
}
else {
Map<String, String[]> parameterMap = webRequest.getParameterMap();
Map<String, String> result = new LinkedHashMap<>(parameterMap.size());
parameterMap.forEach((key, values) -> {
if (values.length > 0) {
result.put(key, values[0]);
}
});
return result;
}
}
}
}
参数解析都通过HandlerMethodArgumentResolverComposite
还有处理返回值的HandlerMethodReturnValueHandlerComposite
也是一样的