Spring之参数解析器

Spring中的参数解析,可以让我们自定义的对处理器的一些参数请求做处理,自定义参数解析主要是通过实现 HandlerMethodArgumentResolver 接口,重写supportsParameter()方法和resolveArgument()方法,并注册解析器,即可启用。

一、自定义参数解析器

重写 HandlerMethodArgumentResolver 接口方法

public class DemoArgResolver implements HandlerMethodArgumentResolver {
   @Override
   public boolean supportsParameter(MethodParameter parameter) {
      System.out.println("supportsParameter " + parameter.getParameterType());
      System.out.println("supportsParameter " + parameter.getParameterName());
      return true;
   }

   @Override
   public Object resolveArgument(MethodParameter parameter,
                          ModelAndViewContainer mavContainer,
                          NativeWebRequest webRequest,
                          WebDataBinderFactory binderFactory) throws Exception {
      System.out.println("resolveArgument " + parameter.getParameterName());
      return null;
   }
}

supportsParameter()方法表示需要自定义的参数类型,返回结果为true则表示需要自定义解析的参数,此时才会执行resolverArgument()方法,对该参数做操作,返回结果为该参数类型的对象实例。

注册参数解析器

@Configuration
public class ResolverConfig implements WebMvcConfigurer {

   @Override
   public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
      resolvers.add(new DemoArgResolver());
   }
}

这样就是实现了一个简单的自定义参数解析器,我们开发中可以自己重写参数解析器中的方法逻辑。

二、参数解析器源码解析

在IDEA工具中,我们通过debug断点调试,执行到如下代码中

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

   private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();

   private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
         new ConcurrentHashMap<>(256);
   // 其他略......	

   @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);
   }

   
   @Nullable
   private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
      HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
      if (result == null) {
         for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
            if (resolver.supportsParameter(parameter)) {
               result = resolver;
               this.argumentResolverCache.put(parameter, result);
               break;
            }
         }
      }
      return result;
   }

}

supportsParameter()方法中调用了getArgumentResolver()方法,每次执行自定义的supportsParameter()方法,都会将其设置到argumentResolverCache变量中,下次则直接获取,不会再次执行,也就是改方法只会在需要时调用一次,再次需要时不在调用。系统自定义的参数解析器HandlerMethodArgumentResolverComposite 则会在InvocableHandlerMethod的对象中调用。

public class InvocableHandlerMethod extends HandlerMethod {

	private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();

	@Nullable
	public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Arguments: " + Arrays.toString(args));
		}
		return doInvoke(args);
	}

	protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		MethodParameter[] parameters = getMethodParameters();
		if (ObjectUtils.isEmpty(parameters)) {
			return EMPTY_ARGS;
		}

		Object[] args = new Object[parameters.length];
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			args[i] = findProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
			if (!this.resolvers.supportsParameter(parameter)) {
				throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
			}
			try {
				args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
			}
			catch (Exception ex) {
				// Leave stack trace for later, exception may actually be resolved and handled...
				if (logger.isDebugEnabled()) {
					String exMsg = ex.getMessage();
					if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
						logger.debug(formatArgumentError(parameter, exMsg));
					}
				}
				throw ex;
			}
		}
		return args;
	}
}

在getMethodArgumentValues()方法中获取方法的所有参数对象MethodParameter,循环遍历参数,调用HandlerMethodArgumentResolverComposite 对象的supportsParameter方法,然后再调用了resolverParameter()解析参数,获取返回解析之后的参数对象。

三、自定义参数解析器案例

例如我们常见的 @RequestParam@PathVariable@RequestBody等参数注解都有对应的参数解析器,在平常的业务开发中,我们也可以更据自己的需要,合理的定制化自己所需的参数解析器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值