在运行时将列表元素添加到Spring属性

时间:2019-07-08 22:13:05

标签: spring-boot spring-properties

我有一个application.yml文件,内容如下:

topics:
  input:
    - name: topic1
      partitions: 3
      replicas: 1
    - name: topic2
      partitions: 6
      replicas: 2

我希望能够在运行时更新或添加新的主题对象。

我尝试了以下方法来更新现有对象:

java -jar app.jar --topics.input[0].name="topicX"

以及以下用于将另一个对象添加到列表中的内容:

java -jar app.jar --topics.input[2].name="topicX" --topics.input[2].partitions=6 --topics.input[2].replicas=2

我通过以下方式访问属性:

@Component
@ConfigurationProperties(prefix = "topics")
@Validated
public class TopicsConfiguration {

  @NotEmpty
  @NotNull
  private List<TopicConfiguration> input = new ArrayList<>();

  public List<TopicConfiguration> getInputTopics() {
    return input;
  }

  public void setFacts(List<TopicConfiguration> input) {
    this.input = input;
  }

}

TopicConfiguration只是列出了3个字段的POJO。

当我不尝试在运行时修改任何属性对象时,它的工作方式完全符合我的预期,但是我根本无法更新属性列表。当我尝试更新现有对象时,我得到了NPE。当我尝试将新对象添加到列表中时,我得到:

Property: topics.input[2].name
    Value: lmnop
    Origin: "topics.input[2].name" from property source "commandLineArgs"
    Reason: The elements [topics.input[2].name,topics.input[2].partitions,topics.input[2].replicas] were left unbound.

我只想知道是否有任何方法可以在运行时更新或向列表中添加元素,以便我项目的用户如果要更新此配置,则不必修改application.yml

2 个答案:

答案 0 :(得分:1)

okey,所以我做了一些研究和测试,并提出了以下建议:

您无法更新application.yml中的已定义列表

如果您运行:

java -jar myApp.jar -my-list[2].name=foo

它将失败,因为一旦您想要传递列表,该列表就会覆盖application.yml中的当前列表,并且当索引0和1都没有任何内容时,您试图传递列表中的第三项

它不是动态列表,而是一个数组。

您需要传递整个列表:

java -jar myApp.jar -my-list[0].name=foo -my-list[1].name=bar -my-list[2].name=foobar 

因此,如果要从cmd中传递列表,则必须始终从头开始定义列表。

答案 1 :(得分:0)

因此,您想动态地在Spring Boot应用程序中重新加载application.propertiesapplication.yml,而不必使另一个代码提交到另一个部署中吗?如果我了解的没错,那么这就是您的方法。

阅读这些链接,并在Spring Boot Actuator Reload PropertiesSpring Scheduling上搜索更多Google链接。我们无法为您提供经过编写的代码来使其正常工作,但是有很多示例可供研究和尝试。

链接:

  1. Actuator Refresh
  2. Spring Scheduling

如果我是您,我希望使用Actuator方法,因为它可以避免混乱并且更干净。