@ConstructorBinding配置在实现Validator接口时不触发验证

nev*_*ind 5 spring-validator spring-boot spring-properties

我正在使用spring-boot-starter-parent版本2.4.4.

我正在尝试使用和不使用类型化配置进行验证@ConstructorBinding

这是一个经过验证并正确停止应用程序运行的类型化配置。它不使用@ConstructorBinding,而是使用 getter/setter 样式:

  @ConfigurationProperties("app")

  @Validated

  @Getter
  @Setter
  public static class AppProperties implements org.springframework.validation.Validator {

    private int someProp = 10;

    @Override
    public boolean supports(Class<?> aClass) {
      return aClass.isAssignableFrom(getClass());
    }

    @Override
    public void validate(Object o, Errors errors) {
      AppProperties appProperties = (AppProperties) o;

      if (appProperties.getSomeProp() < 100) {
        errors.rejectValue("someProp", "code", "Number should be greater than 100!");
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

网络应用程序已设置,@ConfigurationPropertiesScan因此一切正常。运行时,正如预期的那样,我得到了这个:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'app' to com.example.demo.DemoApplication$AppProperties failed:

    Property: app.someProp
    Value: 10
    Reason: Number should be greater than 100!
Run Code Online (Sandbox Code Playgroud)

伟大的。但我是构造函数注入的粉丝,我想将其重构为使用@ConstructorBinding. 我们开始做吧:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'app' to com.example.demo.DemoApplication$AppProperties failed:

    Property: app.someProp
    Value: 10
    Reason: Number should be greater than 100!
Run Code Online (Sandbox Code Playgroud)

这次,应用程序启动。没有错误。我期望应用程序不会运行,并且对我来说会得到相同的启动错误,因为注入的someProp0(我没有在任何地方声明它),所以根据我的验证显然是无效的。如果我调试一下AppProperties,该someProp成员确实是0


我做了一些研究,但我是一个 Spring 菜鸟,无法找出原因。以下是我的一些发现:

  • 尽管我同意 Spring 开发人员的观点,即 aorg.springframework.validation.Validator应该是一个独立的对象,旨在验证许多对象,但事实上,Validator 绑定到实现Validator. 请参阅此处:GitHub 链接。该代码表示​​“如果您的类实现了 Validator,我将在创建您的 bean 时使用特殊的绑定器来验证它”。
  • 使用 getter/setter 样式,您可以从- JSR-303 和获得两个验证器,而使用只能获得一个- JSR-303。这是为什么?好吧,因为在使用构造函数绑定时,目标 - 我的类型化配置 - 还没有值:请参阅此处的条件org.springframework.boot.context.properties.ConfigurationPropertiesBinder#getValidators()Validator@ConstructorBinding
  • 与上述相关,在 ctor 绑定上,此条件为 false,因此被绕过:condition Bypassed
  • 根据策略的不同,bean 的创建方式肯定会有所不同:
    • ctor 绑定在这里触发这个方法,它创建一个“值对象”(不确定这在 Spring 的上下文中意味着什么)
    • 相反,getter/setter 会在此处触发此方法。

这可能与bean ctor的创建时间早、setter创建时间晚有关。不过,目前这只是好奇心。

有什么想法如何使用 来验证构造函数绑定的类型配置吗Validator?如果这不是正确的方法,你会怎么做?

谢谢阅读。