Spring参数解析——自定义HandlerMethodArgumentResolver

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() 主要工作
  1. 进行参数解析 getMethodArgumentValues
  2. 执行方法调用 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() 主要工作
  1. 获取方法参数 MethodParameter
  2. 遍历每个参数找到对应 supportsParameter 的resolver
  3. 执行参数解析 resolveArgument 封装到 args
  4. 返回解析后的参数 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)

拓展

Reference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值