在我们写代码的时候有时候需要做入参,出参映射,如果你们公司的网关已经实现了这个功能,那再好不过,如果没有,需要你在自己的某个服务中自己通过代码实现,这个时候Spring中的ArgumentResolver和ReturnValue类,就派上了用场。
一、ArgumentResolver源码分析
我们一个看看在Spring中,一个请求过来的时候什么时候使用到了ArgumentResolver。
在spring-boot中,默认情况下,当一个请求进来的时候,先进入DispatcherServlet,然后在handle方法中进入了RequestMappingHandlerAdapter的invokeHandlerMethod方法,一直下去会进入了InvocableHandlerMethod的getMethodArgumentValues方法,其中有这样一段:
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
如果你再参数前面加入了@RequestBody,就会进入RequestResponseBodyMethodProcessor的resolveArgument方法。
其时序图如下:
ReturnValueHandler是在返回的时候渲染的。不做过多解析了就。
二、注册时候的注意事项
如果你注册ArgumentResolver或ReturnValueHandler的时候像下面这样:
// @Bean
// public WebMvcConfigurer corsConfigurer() {
// return new WebMvcConfigurer() {
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new InPramMappingInterceptor())
.addPathPatterns("/**");
}
//
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
List<HandlerMethodArgumentResolver> adapterArgumentResolvers = requestMappingHandlerAdapter.getArgumentResolvers();
System.out.println(adapterArgumentResolvers.size());
// resolvers.add(new RequestResponseBodySkinDTOMethodProcessor());
}
//
//
// @Override
// public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers){
// }
// };
// }
你会发现有时候执行不到你的ArgumentResolver,这是因为被别的拦截了,你需要像如下这样注册,才可以生效:
@Resource
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
@PostConstruct
public void init() {
final List<HandlerMethodReturnValueHandler> originalHandlers = new ArrayList<>(requestMappingHandlerAdapter.getReturnValueHandlers());
// Add customed handler BEFORE the HttpEntityMethodProcessor to enable JsonReturnHandler !!
final int httpEntityPos = obtainValueHandlerPosition(originalHandlers, HttpEntityMethodProcessor.class);
HttpEntityMethodProcessor httpEntityMethodProcessor = (HttpEntityMethodProcessor) originalHandlers.get(httpEntityPos);
originalHandlers.add(httpEntityPos - 1, new ResponseEntitySkinDTOReturnValueHandler(httpEntityMethodProcessor));
requestMappingHandlerAdapter.setReturnValueHandlers(originalHandlers);
//add argumentResolvers
final List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(requestMappingHandlerAdapter.getArgumentResolvers());
final int requestbodyPos = obtainResolverPosition(resolvers, RequestResponseBodyMethodProcessor.class);
resolvers.add(requestbodyPos - 1, new RequestBodySkinDTOArgumentResolver());
requestMappingHandlerAdapter.setArgumentResolvers(resolvers);
return;
}
//查找指定hander在数组中的位置
private int obtainValueHandlerPosition(final List<HandlerMethodReturnValueHandler> originalHandlers, Class<?> handlerClass) {
for (int i = 0; i < originalHandlers.size(); i++) {
final HandlerMethodReturnValueHandler valueHandler = originalHandlers.get(i);
if (handlerClass.isAssignableFrom(valueHandler.getClass())) {
return i;
}
}
return -1;
}
//查找指定resolver在数组中的位置
private int obtainResolverPosition(final List<HandlerMethodArgumentResolver> resolvers, Class<?> resloverClass) {
for (int i = 0; i < resolvers.size(); i++) {
final HandlerMethodArgumentResolver resolver = resolvers.get(i);
if (resloverClass.isAssignableFrom(resolver.getClass())) {
return i;
}
}
return -1;
}
这是为什么呢,这样从加载RequestMapingHandlerAdapter的时候开始分析了。
三、RequestMappingHandlerAdapter加载resolver和handler
在RequestMappingHandlerAdapter中,会执行如下方法加载resolver和Handler:
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache();
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
在上面的getDefaultArgumentResolvers方法中,会先加载Spring默认的,然后再加载用户自己配置的,所以用户自己配置的有可能会被拦截,而通过之前说的方式,可以让自己配置的生效。