Springboot @GetMapping 自动接收对象参数源码分析
Posted OkidoGreen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Springboot @GetMapping 自动接收对象参数源码分析相关的知识,希望对你有一定的参考价值。
偶然发现这样也可以接收对象类型的入参,代码如下
@GetMapping("obj")
public void obj(DataDto dataDto)
System.out.println(dataDto.getName()+"-"+dataDto.getValue());
http://localhost:9999/obj?name=1&value=2
1-2
springboot中会在启动时 加载许多 argumentResolver 和 returnValueHandler ,可以自行查看
RequestMappingHandlerAdapter # getDefaultArgumentResolvers 、getDefaultReturnValueHandlers方法,这里不再赘述,核心问题是 到底是哪个HandlerMethodArgumentResolver处理了上述代码中的自动填充逻辑;
根据debug调试最终发现在 getDefaultArgumentResolvers 的最后的兜底策略中进行了处理:
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(this.getMessageConverters(), this.requestResponseBodyAdvice));
....
....
resolvers.add(new ServletModelAttributeMethodProcessor(true));
看一下这个类的源码,首先是他的构造函数,对比上面的DefaultArgumentResolvers,可以明
显地看到 ServletModelAttributeMethodProcessor 其实被添加了2次,同时结合 supportsParameter 方法,可以明显的发现:
第一次构造参数是false,专门用来处理@ModelAttribute注解
第二次是true,专门用来处理 入参 前面没有 注解的情况:
public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor
public ServletModelAttributeMethodProcessor(boolean annotationNotRequired)
super(annotationNotRequired);
//父类构造,传入 true表示 方法参数 没有 类似 @RequestParam、@PathVariable 的注解
public ModelAttributeMethodProcessor(boolean annotationNotRequired)
this.annotationNotRequired = annotationNotRequired;
public boolean supportsParameter(MethodParameter parameter)
return parameter.hasParameterAnnotation(ModelAttribute.class) || this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType());
所以ServletModelAttributeMethodProcessor的解析处理
其实都是依靠父类 ModelAttributeMethodProcessor 来解决的,
接下来看核心的 resolveArgument 方法,看一下如何转换为 我们 Controller 中 API的入参对象:
public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception
Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
String name = ModelFactory.getNameForParameter(parameter);
ModelAttribute ann = (ModelAttribute)parameter.getParameterAnnotation(ModelAttribute.class);
if (ann != null)
mavContainer.setBinding(name, ann.binding());
Object attribute = null;
BindingResult bindingResult = null;
if (mavContainer.containsAttribute(name))
attribute = mavContainer.getModel().get(name);
else
try
attribute = this.createAttribute(name, parameter, binderFactory, webRequest);
catch (BindException var10)
if (this.isBindExceptionRequired(parameter))
throw var10;
if (parameter.getParameterType() == Optional.class)
attribute = Optional.empty();
else
attribute = var10.getTarget();
bindingResult = var10.getBindingResult();
if (bindingResult == null)
//根据api的对象入参 生成 databinder
//其中的属性target就是 controller中 api的入参对象,等待后续属性填充
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null)
if (!mavContainer.isBindingDisabled(name))
//将request中的querystring 与 binder中的 target 入参对象的属性进行绑定
//这个方法调用完成后,其实binder中的target属性 已经填充完毕了
this.bindRequestParameters(binder, webRequest);
this.validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter))
throw new BindException(binder.getBindingResult());
if (!parameter.getParameterType().isInstance(attribute))
attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
//通过binder生成 bindingresult,其中包含了 target入参对象等
bindingResult = binder.getBindingResult();
//获取target对象,生成map,key=target对象类名,value=target对象
Map<String, Object> bindingResultModel = bindingResult.getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return attribute;
至此,request请求中的querystring参数已通过绑定装配 变成了 API 的入参对象,后续进行实际的方法调用
以上是关于Springboot @GetMapping 自动接收对象参数源码分析的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot的映射(@RequestMapping@GetMapping与@PostMapping)
SpringBoot 中常用注解@PathVaribale/@RequestParam/@GetMapping介绍