将yaml合并在多个弹簧轮廓上

时间:2017-08-31 02:09:09

标签: java spring spring-boot yaml

我在本文末尾提供了一个解决方案但是这样做的首选方法是什么?我的用例是跨多个配置文件读取yaml并合并到映射到java类的单个配置。

描述此问题的示例项目位于https://github.com/balamuru/yaml-pojo-merge

例如。考虑以下POJO

public class Credentials {
    private String user;
    private String password;
}

这可以通过多种方式组合成一个集合

Credential对象的集合 Credential对象的直接描述性实例

public class AllCredentials {
    private List<Credentials> credentials; //won't merge (will override instead) because spring doesn't know which original Credential list item to over-ride when an override value is supplied in the profile (for instance , if only one password is supplied, spring doesn't know whether to update list item 1 or 2 etc)
}
public class FamilyCredentials {
    private Credentials husband; //the corresponding yaml is determinate - and spring can determine exactly what field to update
    private Credentials wife;
} 

默认和配置文件特定的YML文件中的相应表示如下

com.foo.bar.allcreds:
  credentials:
    - user: bill
      password: bi123
    - user: hilary
      password: h123

com.foo.bar.famcreds:
  husband:
    user: bill
    password: bi123
  wife:
    user: hilary
    password: h123

---
spring.profiles: prod
com.foo.bar.allcreds:
  credentials:
    - password: monic@
    - password: my_em@ilz

com.foo.bar.famcreds:
  husband:
    password: monic@
  wife:
    password: my_em@ilz    

据观察,在List的情况下,Spring无法确定更新密码的凭证实例(即使用户名已被提供),因为它提供了一个项目列表,并且不能保证所有项目提供,或(即使按此顺序)

OTOH,FamilyCredentials YAML完美地解析,因为密码字段的路径格式正确且确定。

如果处理无界数据结构,解决方案是使用允许我们限定被修改的段(即散列映射)的内容。这是一个可行的数据结构(键“mr_prez”和“first_lady”可以精确解析更新的合格yaml属性。)

这个项目中的测试用例证实了这一点。

public class AllCredentialsMap {
    private Map<String, Credentials> credentials;
and the corresponding yaml segments

com.foo.bar.allcredsmap:
  credentials:
    mr_prez:
      user: bill
      password: bi123
    first_lady:
      user: hilary
      password: h123

---
spring.profiles: prod

com.foo.bar.allcredsmap:
  credentials:
    mr_prez:
      password: monic@
    first_lady:
      password: my_em@ilz  

1 个答案:

答案 0 :(得分:0)

我厌倦了你的项目,请看下面的变化:

配置元数据键(com.foo.bar.allcreds)如果在活动配置文件下找到相同的键但是您必须遵循相同的列表模式,则会被覆盖:

com.foo.bar.allcreds:
  credentials:
    - user: bill
      password: monic@
    - user: hilary
      password: my_em@ilz


@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "com.foo.bar.allcreds")
public class AllCredentials {
    private List<Credentials> credentials;

    public List<Credentials> getCredentials() {
        return credentials;
    }

    public void setCredentials(List<Credentials> credentials) {
        this.credentials = credentials;
    }

}


public class Credentials {

    private String user;
    private String password;

}

application.yml:

com.foo.bar.allcreds:
  credentials:
    - user: bill
      password: monic@
    - user: hilary
      password: my_em@ilz

测试:

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("prod")
public class YamlPojoMergeApplicationTests {



    @Autowired
    AllCredentials allCredentials;



    //This works
    @Test(expected = AssertionError.class)
    public void testAllCredentials() {
        Credentials credentials1 = allCredentials.getCredentials().get(0);
        Credentials credentials2 = allCredentials.getCredentials().get(1);

        assertThat(credentials1.getUser(), is(equalTo("bill")));
        assertThat(credentials1.getPassword(), is(equalTo("monic@")));

        assertThat(credentials2.getUser(), is(equalTo("hilary")));
        assertThat(credentials2.getPassword(), is(equalTo("my_em@ilz")));
    }

}

关于合并的一些有用的讨论(已弃用),您可以在此处找到它:

https://github.com/spring-projects/spring-boot/issues/2750