小议SpringMvc参数绑定流程

2022-08-11 16:46:09 浏览数 (1)

在SpringMvc开发过程中,我们通常会用一种注解的参数校验法。因为用起来很方便。所以很受欢迎。今天就扒一扒这个注解异常校验的流程。作者通过不断的debug,终于找到北了。它在dispatchservlet中,总的调度入口如图所示。

最后在InvocableHandlerMethod类中获取传入的参数。

代码语言:javascript复制
    protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        MethodParameter[] parameters = this.getMethodParameters();
        if (ObjectUtils.isEmpty(parameters)) {
            return EMPTY_ARGS;
        } else {
            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) {
//查看是否有何时的解析器
                    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 var10) {
                        if (logger.isDebugEnabled()) {
                            String exMsg = var10.getMessage();
                            if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                                logger.debug(formatArgumentError(parameter, exMsg));
                            }
                        }


                        throw var10;
                    }
                }
            }


            return args;
        }
    }

在此类的开头,我们看到这里可以设置很多解析器

代码语言:javascript复制
代码语言:javascript复制
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {
    private final ListargumentResolvers =new ArrayList();
    private final Map, HandlerMethodArgumentResolver> argumentResolverCache = new ConcurrentHashMap(256);

    public HandlerMethodArgumentResolverComposite() {
    }
//添加解析器
    public HandlerMethodArgumentResolverComposite addResolver(HandlerMethodArgumentResolver resolver) {
        this.argumentResolvers.add(resolver);
        return this;
    }
//添加解析器
    public HandlerMethodArgumentResolverComposite addResolvers(@Nullable HandlerMethodArgumentResolver... resolvers) {
        if (resolvers != null) {
            Collections.addAll(this.argumentResolvers, resolvers);
        }

        return this;
    }

我们看到这块选出来的是ServletModelAttributeMethodProcessor,然后使用这个解析器进行参数校验。

写了一下午,没保存.....

上边写的这些其实还是没有分析到精髓上,我们大概的了解了一下流程,但是对于像@NotNull等注解的具体解析都没有找到,当然也不知道如何自定义一个注解解析器,并添加到viltaler中。所以上边的分析并不是很好,迷迷糊糊的。但是作者在DispatchServlet中发现了一个异常处理器。其是可以定义多个的,而且会轮询去执行,知道出现一个可以处理该异常的解析器就停止。

作者查看源码,发现在DispatchServlet初始化的时候,从Spring上下文中获取了这些解析器,代码如下图所示。

这块的意思就是说咋通过实现接口HandlerExceptionResolver,然后将其注入到SpringIoc中即可让SpringMvc去执行我们自定义的异常处理机制。也就是全局异常处理,但势必需要让我们自定义的异常处理器执行的比较早。所以我们实践一下。

代码语言:javascript复制
@Component
public class MyHand implements HandlerExceptionResolver, Ordered {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        System.out.println("12");
        e.printStackTrace();
        System.out.println(o.toString());
        return null;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

我们看一下效果:

最近优点懒,睡得的挺好,一天能睡很久。文章好久都没更了,这是一个坏味道。希望早日回归正常态。

天气很热,注意开空调,节约用电~

0 人点赞