HandlerMethodArgumentResolver
Strategy interface for resolving method parameters into argument values in the context of a given request.
/**
* 判断 HandlerMethodArgumentResolver 是否支持 MethodParameter
* (PS: 一般都是通过 参数上面的注解|参数的类型)
*
**/
boolean supportsParameter(MethodParameter parameter);
/**
* 获取数据, 参数绑定,解析出方法上的参数
**/
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
主要用途:
- 统一封装登录的用户信息
- 进行数据绑定,参数验证
Code
todo resolver 更改 解析过程
// resolver
@Component
public class ParameterResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(Param.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
try {
Class clazz = parameter.getParameterType();
Object object = buildRequestParam(webRequest, clazz);
String name = Conventions.getVariableNameForParameter(parameter);
// handleRequestParam(webRequest, object);
WebDataBinder webDataBinder = binderFactory.createBinder(webRequest, object, name);
validAnnotation(parameter, webDataBinder, object);
return object;
} catch (BindException e) {
log.info("resolveArgument exception: {}", e.toString());
throw bindException2FieldException(e);
} catch (Exception e) {
log.error("resolveArgument exception: {}", e);
throw e;
}
}
}
// Controller
@RequestMapping(value = "resolverValidated", method = {RequestMethod.GET,RequestMethod.POST})
public Result resolverValidated(@Param @Validated PersonDO person) {
System.out.println(person);
return new Result<>(person);
}
@PostMapping("resolverValidatedBody")
public Result resolverValidatedBody(@Param @Validated @RequestBody PersonDO person) {
System.out.println(person);
return new Result<>(person);
}
// 注册resolver
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Autowired
private ApplicationContext context;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
Map<String, HandlerMethodArgumentResolver> beans = context.getBeansOfType(HandlerMethodArgumentResolver.class);
beans.forEach((name, bean) -> resolvers.add(bean));
}
}
源码跟踪
这次源码跟踪从 DispatcherServerlet.doService()方法开始
- 概览
- 调用方法栈
// 处理请求
DispatcherServlet
protected void doService(HttpServletRequest request, HttpServletResponse response)
// 分发请求到对应的handler
DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
AbstractHandlerMethodAdapter
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
RequestMappingHandlerAdapter
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)
// Invoke the RequestMapping handler method
RequestMappingHandlerAdapter
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)
//Invoke the method and handle the return value
ServletInvocableHandlerMethod
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)
// Invoke the method after resolving its argument values in the context of the given request.
InvocableHandlerMethod
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs)
// Get the method argument values for the current request.
InvocableHandlerMethod
private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs)
// Whether the given MethodParameter is supported by any registered HandlerMethodArgumentResolver.
HandlerMethodArgumentResolverComposite
public boolean supportsParameter(MethodParameter parameter)
// Find a registered HandlerMethodArgumentResolver that supports the given method parameter.
HandlerMethodArgumentResolverComposite
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter)
// 自定义实现 当前resolver是否支持 MethodParameter 的解析
ParameterResolver
public boolean supportsParameter(MethodParameter parameter)
主要方法
- InvocableHandlerMethod.invokeForRequest() 主要工作
- 进行参数解析 getMethodArgumentValues
- 执行方法调用 doInvoke
# InvocableHandlerMethod
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
return returnValue;
}
- InvocableHandlerMethod.getMethodArgumentValues() 主要工作
- 获取方法参数 MethodParameter
- 遍历每个参数找到对应 supportsParameter 的resolver
- 执行参数解析 resolveArgument 封装到 args
- 返回解析后的参数 args
private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
}
throw ex;
}
}
if (args[i] == null) {
throw new IllegalStateException("Could not resolve method parameter at index " +
parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() +
": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
}
}
return args;
}
HandlerMethodArgumentResolverComposite 是所有参数解析器的一个集合
项目启动时会将所有的参数解析器放到HandlerMethodArgumentResolverComposite
- 参数解析调用方法栈
// 获取匹配的resolver 执行解析
HandlerMethodArgumentResolverComposite
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)
// 最终的解析方法
ParameterResolver
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory)