HandlerMethodArgumentResolver(三):基于消息转换器的参数处理器【享学Spring MVC】 (4)

从代码里可以直观的看到:有了抽象父类后,子类需要做的事情已经很少了,只需要匹配参数类型、做不同的返回而已。
关于它俩的使用案例,此处不用再展示了,因为各位平时工作中都在使用,再熟悉不过了。但针对他俩的使用,我总结出如下几个小细节,供以参考:

@RequestBody/HttpEntity它的参数(泛型)类型允许是Map

方法上的和类上的@ResponseBody都可以被继承,但@RequestBody不可以

@RequestBody它自带有Bean Validation校验能力(当然需要启用),HttpEntity更加的轻量和方便

HttpEntity/RequestEntity所在包是:org.springframework.http,属于spring-web
@RequestBody位于org.springframework.web.bind.annotation,同样属于spring-web

最后还落了一个ErrorsMethodArgumentResolver,在这里补充一下:

ErrorsMethodArgumentResolver

它用于在方法参数可以写Errors类型,来拿到数据校验结果。

public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { Class<?> paramType = parameter.getParameterType(); return Errors.class.isAssignableFrom(paramType); } @Override @Nullable public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { Assert.state(mavContainer != null, "Errors/BindingResult argument only supported on regular handler methods"); ModelMap model = mavContainer.getModel(); String lastKey = CollectionUtils.lastElement(model.keySet()); // 只有@RequestBody/@RequestPart注解的 这里面才会有值 if (lastKey != null && lastKey.startsWith(BindingResult.MODEL_KEY_PREFIX)) { return model.get(lastKey); } // 简单的说:必须有@RequestBody/@RequestPart这注解标注,Errors参数才有意义 throw new IllegalStateException( "An Errors/BindingResult argument is expected to be declared immediately after " + "the model attribute, the @RequestBody or the @RequestPart arguments " + "to which they apply: " + parameter.getMethod()); } } Spring MVC参数处理器的注册与顺序

到这里,一个不落的把Spring MVC内置提供的参数处理器ArgumentResolver说了个遍。
前面我有提到过:参数处理对处理器的顺序是敏感的,因此我们需要关注Spring MVC最终的执行顺序,这时候我们的聚合容器HandlerMethodArgumentResolverComposite就出场了:

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver { private final List<HandlerMethodArgumentResolver> argumentResolvers = new LinkedList<>(); // 具有缓存 private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache = new ConcurrentHashMap<>(256); ... // @since 4.3 木有任何地方调用 public void clear() { this.argumentResolvers.clear(); } // getArgumentResolver()方法是本文的核心 @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); } ... // 这块逻辑保证了每个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; } }

缺省情况Spring MVC注册的处理器(顺序)如下:

在这里插入图片描述


它初始化处的代码如下:

RequestMappingHandlerAdapter: @Override public void afterPropertiesSet() { ... // 26个,详见方法getDefaultArgumentResolvers if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } // 12个 详见方法getDefaultInitBinderArgumentResolvers if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } ... }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywsgx.html