添加相同类型的自定义解析器时,默认参数解析器会发生什么情况?

Ant*_*sss 3 spring spring-mvc

所以我想将最大可分页大小值限制为 10(示例值),我可以这样做:

@Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        super.addArgumentResolvers(argumentResolvers);
        PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver();
        resolver.setMaxPageSize(10);
        argumentResolvers.add(resolver);
    }
}
Run Code Online (Sandbox Code Playgroud)

和delcare控制器方法像这样

   @RequestMapping(name = "list")
    public String listUsers(@PageableDefault(size = 5, page = 0) Pageable pageable) {
Run Code Online (Sandbox Code Playgroud)

事实上,这会起作用,我无法将页面大小设置为> 10,但我很好奇为什么?Spring 创建的发生了什么PageableHandlerMethodArgumentResolver?为什么要考虑此实例而不是默认实例?毕竟,我不会在这里更换解析器,只是添加一个新的解析器。

var*_*ren 6

1. 配置阶段

当您WebMvcConfigurerAdapter在 中扩展和添加自定义解析器时addArgumentResolvers(跳过大量配置代码),您实际上是将它们添加到RequestMappingHandlerAdapter RequestMappingHandlerAdapter bean,它在内部保存初始化期间提供的所有解析器的列表。(WebMvcConfigurationSupport)。之后它们与默认解析器组合。从源代码中可以看到,PageableHandlerMethodArgumentResolver它实际上并不是默认解析器列表的一部分,而是来自某个配置类。在我的例子中(下面的屏幕截图),spring-boot-starter-data-rest配置类提供了不同版本的 PageableHandler:HateoasPageableHandlerMethodArgumentResolver

2. 解析器顺序

自定义解析器在内置解析器之后排序(来源)。因此,让我们检查一下并调用一些控制器,但首先在RequestMappingHandlerAdapter.invokeHandlerMethod()中放置断点。从这里我们可以看到内部状态RequestMappingHandlerAdapter

在此输入图像描述

我突出显示了自定义解析器MyPageableHandlerMethodArgumentResolver,其注册方式与您在问题代码中的注册方式相同。

实际解析参数的代码位于HandlerMethodArgumentResolverComposite中。这是一个简单的循环,这意味着HandlerMethodArgumentResolver将使用第一个注册的

for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers)
    if (methodArgumentResolver.supportsParameter(parameter)) {
        result = methodArgumentResolver;
        this.argumentResolverCache.put(parameter, result);
        break;
    }
Run Code Online (Sandbox Code Playgroud)

从源代码中可以看到,结果会被缓存,并且不会对相同的参数类型再次进行迭代。