[spring-projects/spring-boot]有时需要在 ConfigurationProperties 类的构造函数上使用 @Autowired,以确保生成正确的元数据

2024-06-26 464 views
9

使用 Boot 3.0.2,我们看到这样一种行为:只有通过构造函数绑定注入的属性才会作为类spring-configuration-metadata.json.中任何其他属性的一部分生成ConfigurationProperties,而类中的任何其他属性都会被省略。

假设我们有以下ConfigurationProperties课程。

@ConfigurationProperties("test.properties")
public class TestProperties {

    private final MyData myData;

    private String custom;

    public TestProperties(MyData myData) {
        this.myData = myData;
    }

    public MyData getMyData() {
        return myData;
    }

    public String getCustom() {
        return custom;
    }

    public void setCustom(String custom) {
        this.custom = custom;
    }
}

record MyData(String data) {}

我们在生成的类中看到以下内容:上述类中的属性spring-configuration-metadata.json. 不存在。customConfigurationProperty

{
  "groups": [
    {
      "name": "test.properties",
      "type": "com.example.demo.TestProperties",
      "sourceType": "com.example.demo.TestProperties"
    }
  ],
  "properties": [
    {
      "name": "test.properties.my-data",
      "type": "com.example.demo.MyData",
      "sourceType": "com.example.demo.TestProperties"
    }
  ],
  "hints": []
}

此问题与https://github.com/spring-cloud/spring-cloud-stream/issues/2640有关

回答

6

先生您好,我是开源贡献的新手。我已经了解 Java,我的技术栈和工具包括 C、C++、Python、Java、JavaScript、HTML、CSS、SQL、Bootstrap、ReactJS、ExpressJS、NodeJS 和 Git。我需要您提供一点帮助,以便为这些出色的项目做出贡献。

0

感谢 @itsarraj 的提议,但问题跟踪器并不是寻求建议的最佳场所。我们有很多人订阅了问题,他们每个人都会收到通知。如果您有兴趣提供帮助,请查看CONTRIBUTING.adoc存储库中的文件,并留意带有status: first-timers-only或标记的问题status: ideal-for-contribution。如果您有更多问题,请加入我们 gitter.im。

5

@sobychacko 您是否期望test.properties.my-data.datatest.properties.custom在构建时都记录下来并在运行时进行绑定?我们不支持同一类的构造函数绑定和 JavaBean 样式绑定,因此这行不通。您只能test.properties.my-data.data通过构造函数绑定或test.properties.customJavaBean 样式绑定,但不能同时通过两者。

8

@wilkinsona 感谢您的回复。当我与 @philwebb 讨论这个问题时,我认为可能有办法绕过这个限制。我的期望是构造函数绑定和 JavaBean 样式可以共存。在 Spring Cloud Stream 的 Kafka 绑定器中,我们有一个ConfigurationProperties使用这两种方法的类。看来我们需要删除KafkaProperties.cc @garyrussell的构造函数注入

9

看起来,使用的构造函数KafkaProperties早于 Boot 对构造函数绑定的支持,因此了解其原始意图会很有趣。

KafkaBinderConfigurationProperties定义为@Bean,注入 Boot 的一个实例KafkaProperties。它们KafkaProperties不受构造函数约束,也不是spring.cloud.stream.kafka.binder命名空间的一部分,因此我认为它们不应该被记录为这样。

据我所知,这里的问题是,生成元数据的注释处理器可能会错误地确定将使用构造函数绑定,而实际上将执行的是 JavaBean 绑定。@Autowired构造函数应该修复它,但是注释处理器在确定如何绑定类的属性时可能没有考虑到这一点。

3

我尝试了这种@Autowired方法,KafkaProperties,但没有发现任何差异。我们不需要在命名空间KafkaProperties下记录所有单独的属性spring.cloud.stream.kafka.binder。现在发生的情况正好相反,即,由于KafkaProperties使用构造函数绑定,因此所有相关属性都丢失了,从而掩盖了所有其他单独的属性。

0

使用上述TestProperties类,Boot 2.7 生成以下元数据:

{
  "groups": [
    {
      "name": "test.properties",
      "type": "com.example.demo.TestProperties",
      "sourceType": "com.example.demo.TestProperties"
    }
  ],
  "properties": [
    {
      "name": "test.properties.custom",
      "type": "java.lang.String",
      "sourceType": "com.example.demo.TestProperties"
    }
  ],
  "hints": []
}

(由于没有MyDatabean,应用程序也无法启动)。

Boot 3.0 产生以下元数据:

{
  "groups": [
    {
      "name": "test.properties",
      "type": "com.example.demo.TestProperties",
      "sourceType": "com.example.demo.TestProperties"
    }
  ],
  "properties": [
    {
      "name": "test.properties.my-data",
      "type": "com.example.demo.MyData",
      "sourceType": "com.example.demo.TestProperties"
    }
  ],
  "hints": []
}

这是由于3.0 中的检测功能有所改进:@ConstructorBinding

但是,如果您有一个@ConfigurationProperties,并且想要将 bean 注入构造函数而不是绑定它,那么您现在需要添加一个@Autowired注释。

虽然在 Cloud Stream 的 Kafka Binder 中,构造函数注入是手动的@Bean,但这实际上是这里的情况。在 Boot 3.0.2 中,将结果添加@Autowired到构造函数TestProperties会产生以下元数据:

{
  "groups": [
    {
      "name": "test.properties",
      "type": "com.example.demo.TestProperties",
      "sourceType": "com.example.demo.TestProperties"
    }
  ],
  "properties": [
    {
      "name": "test.properties.custom",
      "type": "java.lang.String",
      "sourceType": "com.example.demo.TestProperties"
    }
  ],
  "hints": []
}

一切似乎都按预期进行,并且对元数据生成产生了预期的效果。这与推断绑定构造函数时考虑@Autowired代码相匹配。@Autowired

@sobychacko 您能否再检查一下这@Autowired是否有效?

1

啊,好的。我确实看到了与上面 Boot 3.0 相同的输出。我会再试@Autowired一次这种方法。我可能没有正确尝试。我会为你确认。

6

现在确实可以添加@Autowired到构造函数中。我想我之前将添加@Autowired到构造函数参数中,但没有成功。您现在可以关闭此问题了。抱歉打扰了,感谢您的帮助!

7

谢谢,@sobychacko。我将暂时搁置这个问题,因为我想与团队讨论一下,看看我们能否找到一种方法来避免@Autowired不必要的问题。为了让元数据生成正常工作,您需要将其添加到实际上不会用于自动装配的构造函数中(因为您要从方法中手动调用它@Bean),这并不理想。

7

我们将研究一种表示应该使用 bean 绑定的方法,但这种方法并不适用@Autowired。我们正在考虑使用枚举@ConfigurationProperties

6

我开始考虑添加枚举,但对于补丁版本来说,这相当复杂。目前,建议在方法上而不是类上使用@ConfigurationProperties枚举可能更好。@ConfigurationProperties@Bean

7

感谢@sobychacko 的验证,此问题已通过#35564 修复。