java 加载多个 YAML 文件(使用 @ConfigurationProperties?)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34063678/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 22:25:49  来源:igfitidea点击:

Loading multiple YAML files (using @ConfigurationProperties?)

javaspringspring-bootsnakeyaml

提问by Alex

Using Spring Boot 1.3.0.RELEASE

使用 Spring Boot 1.3.0.RELEASE

I have a couple of yaml files that describe several instances of a program. I now want to parse all those files into a List<Program>(Map, whatever), so I can later on search for the most appropriate instance for a given criteria in all the programs.

我有几个 yaml 文件描述了一个程序的几个实例。我现在想将所有这些文件解析成一个List<Program>(地图,无论如何),这样我以后就可以在所有程序中为给定条件搜索最合适的实例。

I like the approach with @ConfigurationPropertiesa lot, and it works good enough for a single yaml-file, but I haven't found a way yet to read all files in a directory using that method.

我很喜欢这种方法@ConfigurationProperties,它对于单个 yaml 文件来说已经足够好了,但是我还没有找到一种方法来使用该方法读取目录中的所有文件。

Current approach working for a single file:

当前适用于单个文件的方法:

programs/program1.yml

name: Program 1
minDays: 4
maxDays: 6

can be read by

可以阅读

@Configuration
@ConfigurationProperties(locations = "classpath:programs/program1.yml", ignoreUnknownFields = false)
public class ProgramProperties {

private Program test; //Program is a POJO with all the fields in the yml.
//getters+setters

I tried changing the locations to an Array listing all of my files locations = {"classpath:programs/program1.yml", "classpath:programs/program2.yml"}as well as using locations = "classpath:programs/*.yml", but that still only loads the first file (array-approach) or nothing at all (wildcard-approach).

我尝试将位置更改为列出我所有文件的数组locations = {"classpath:programs/program1.yml", "classpath:programs/program2.yml"}以及使用locations = "classpath:programs/*.yml",但这仍然只加载第一个文件(数组方法)或根本不加载(通配符方法)。

So, my question is, what is the best way in Spring Boot to load a bunch of yaml files in a classpath-directory and parse them into a (List of) POJO, so they can be autowired in a Controller? Do I need to use Snakeyaml directly, or is there an integrated mechanism that I just haven't found yet?

所以,我的问题是,Spring Boot 中在类路径目录中加载一堆 yaml 文件并将它们解析为(列表)POJO,以便它们可以在控制器中自动装配的最佳方法是什么?我是否需要直接使用 Snakeyaml,或者是否有我还没有找到的集成机制?

EDIT: A working approach is doing it manually:

编辑:一种工作方法是手动进行:

    private static final Yaml yaml = new Yaml(new Constructor(Program.class));
private static final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

try {
        for (Resource resource : resolver.getResources("/programs/*.yml")) {

            Object data = yaml.load(resource.getInputStream());

            programList.add((Program) data);
        }
    }
    catch (IOException ioe) {
        logger.error("failed to load resource", ioe);
    }

回答by mchlfchr

What I am currently doing, as far as I understood your question, is nearly the same. I am having an application.ymland also profile-specific yml files, e.g. application-{profile}.ymlin my src/main/resources. In the application.ymlI have defined the default profile key-values, which are partially overridden by the profile-specific yml files.

据我了解您的问题,我目前正在做的事情几乎相同。我有一个application.yml特定application-{profile}.yml于配置文件的 yml 文件,例如在我的src/main/resources. 在application.yml我定义了默认的配置文件键值,这些键值被特定于配置文件的 yml 文件部分覆盖。

If you want to have a type-safe and well defined access of your YML key/values, then you can use the following approach:

如果您想对 YML 键/值进行类型安全且定义明确的访问,则可以使用以下方法:

 @ConfigurationProperties
 public class AppSettings {
     String name; // has to be the same as the key in your yml file

     // setters/getters

 }

In your Spring-Boot config, you have to add the following annotations onto your config class:

在您的 Spring-Boot 配置中,您必须将以下注释添加到您的配置类中:

@ComponentScan
@EnableAutoConfiguration
@EnableConfigurationProperties( value = { AppSettings.class, SomeOtherSettings.class } )
public class SpringContextConfig {

     @Autowired
     private AppSettings appSettings;

     public void test() {
          System.out.println(appSettings.getName());
     }
}

The @Autowiringis also accessible from other Beans. The other way around (without an extra separated and type-safe class, is to access the YML-values via @Value("${name}").

@Autowiring也与其他豆类访问。另一种方法(没有额外的分离和类型安全的类,是通过@Value("${name}").

To bring it together in a short manner: Yes, it is possible to use several YAML files for your application via Spring-profiles. You define your current active spring profile via command args, programmatically or via your system env (SPRING_PROFILES_ACTIVE=name1,name2). Therefore you can have several application.ymlfiles for each profile (see above).

简而言之:是的,可以通过 Spring-profiles 为您的应用程序使用多个 YAML 文件。您可以通过命令 args、以编程方式或通过系统环境 (SPRING_PROFILES_ACTIVE=name1,name2) 定义当前活动的 spring 配置文件。因此,您可以application.yml为每个配置文件创建多个文件(见上文)。

回答by Mohit

In Spring, it is possible to load multiple configuration properties files using PropertySourceannotation, but not YAML files. See section 26.6.4 in link below:

在 Spring 中,可以使用PropertySource注释加载多个配置属性文件,但不能使用 YAML 文件。请参阅以下链接中的第 26.6.4 节:

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties

However, from your problem, it seems that you can configure all your programs in single YAML and then get all list of programs in a single list.

但是,从您的问题来看,您似乎可以在单个 YAML 中配置所有程序,然后在单个列表中获取所有程序列表。

Sample YAML (all.yaml)

示例 YAML (all.yaml)

programs:
  - name: A
    min: 1
    max: 2
  - name: B
    min: 3
    max: 4

Config.java

配置文件

@Configuration
@ConfigurationProperties(locations={"classpath:all.yaml"})
public class Config{

    private List<Program> programs;

    public void setPrograms(List<Program> programs) {
        this.programs = programs;
    }

    public List<Program> getPrograms() {
        return programs;
    }
}