一尘不染

Spring Boot配置中列表的环境变量

spring-boot

对于我的Spring Boot应用程序,我试图使用保存properties.topicsin
列表的环境变量application.yml(请参见下面的配置)。

properties:
      topics:
        - topic-01
        - topic-02
        - topic-03

我使用配置文件来填充属性bean(请参阅此spring文档),如下所示

import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("properties")
public class ApplicationProperties {
  private List<String> topics = new ArrayList<>();
  public void setTopics(List<String> topics) {
     this.topics = topics;
  }
  public List<String> getTopics() {
     return this.topics;
  }
}

通过使用环境变量,我可以更改列表的内容而无需更改application.yml。但是,到目前为止,我只能在仅环境变量仅包含单个值而不是我的情况下包含值的集合的情况下找到所有示例。

编辑:

为了在@vancleff发表评论后明确指出,我不需要将环境变量的值保存到application.yml

另一个编辑:

I think by oversimplifying my question, I shoot myself in the foot. @LppEdd
answer works well with the example given in my question. However, what happens
if instead of a collection of simple string topic names, I need a bit more
complex structure. For example, something like

properties:
  topics:
    - 
      name: topic-01
      id: id-1
    - 
      name: topic-02
      id: id-2
    - 
      name: topic-03
      id: id-3

阅读 682

收藏
2020-05-30

共1个答案

一尘不染

Suggestion, don’t overcomplicate.

Say you want that list as an Environment variable. You’d set it using

-Dtopics=topic-01,topic-02,topic-03

You then can recover it using the injected Environment Bean, and create a
new List<String> Bean

@Bean
@Qualifier("topics")
List<String> topics(final Environment environment) {
    final var topics = environment.getProperty("topics", "");
    return Arrays.asList(topics.split(","));
}

From now on, that List can be @Autowired.
You can also consider creating your custom qualifier annotation, maybe
@Topics.

Then

@Service
class TopicService {
   @Topics
   @Autowired
   private List<String> topics;

   ...
}

Or even

@Service
class TopicService {
   private final List<String> topics;

   TopicService(@Topics final List<String> topics) {
      this.topics = topics;
   }

   ...
}

What you could do is use an externalized file.
Pass to the environment parameters the path to that file.

-DtopicsPath=C:/whatever/path/file.json

Than use the Environment Bean to recover that path. Read the file content
and ask Jackson to deserialize it

You’d also need to create a simple Topic class

public class Topic {
    public String name;
    public String id;
}

Which represents an element of this JSON array

[
    {
        "name": "topic-1",
        "id": "id-1"
    },
    {
        "name": "topic-2",
        "id": "id-2"
    }
]

@Bean
List<Topic> topics(
        final Environment environment,
        final ObjectMapper objectMapper) throws IOException {
    // Get the file path
    final var topicsPath = environment.getProperty("topicsPath");

    if (topicsPath == null) {
        return Collections.emptyList();
    }

    // Read the file content
    final var json = Files.readString(Paths.get(topicsPath));

    // Convert the JSON to Java objects
    final var topics = objectMapper.readValue(json, Topic[].class);
    return Arrays.asList(topics);
}

enter image description
here

2020-05-30