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等参数注解都有对应的参数解析器,在平常的业务开发中,我们也可以更据自己的需要,合理的定制化自己所需的参数解析器。