合并多个TypeSafe Config文件并在它们全部合并后解析

33

我正在编写测试代码以验证RESTful服务。 我希望能够通过在执行测试之前简单地更改环境变量来将其指向我们的任何不同环境。

我想要合并三个不同的配置文件:

  • conf/env/default.conf - 所有环境的默认配置值
  • conf/env/<env>.conf - 特定于环境的值
  • application.conf - 用户对上述任何内容的覆盖

这样做的想法是我不想把所有东西都放在一个配置文件中,并冒着因错误编辑而导致配置项丢失的风险。 因此,将它们分开并让用户有能力对它们进行覆盖。

这里就变得棘手了:default.conf将包括${references},这些引用是要在<env>.conf中被覆盖的,并且可能会在application.conf中进一步被覆盖。

我需要推迟解析直到所有三者被合并。 我该怎么做?


我已经给了John的答案点赞,它值得在合并配置之前参考https://github.com/lightbend/config#standard-behavior。 - Ravindra
2个回答

51
答案是使用 ConfigFactory.parseResource() 代替 ConfigFactory.load()
以下是最终结果。
private lazy val defaultConfig     = ConfigFactory.parseResources("conf/env/default.conf")
private lazy val environmentConfig = ConfigFactory.parseResources("conf/env/" + env + ".conf" )
private lazy val userConfig        = ConfigFactory.parseResources("application.conf")
private lazy val config = ConfigFactory.load()
                          .withFallback(userConfig)
                          .withFallback(environmentConfig)
                          .withFallback(defaultConfig)
                          .resolve()

2
这里可能需要更明确的说明 https://github.com/typesafehub/config - Carlos Bribiescas
这段代码存在问题:.resolve()将会从环境中获取值,但不会从系统属性中获取。目前还不确定如何解决。 - John Arrowwood
找到了解决方案。编辑答案以反映它。 - John Arrowwood
注意:在上述代码中,使用.load()可能会使userConfig变量变得不必要。但原则已经表达出来了,这是最重要的部分。 - John Arrowwood
4
你应该使用.empty()而不是.load()来确保defaultConfig被用作__fallback__. - ShahinSorkh
我肯定希望它能够获取环境变量和系统属性。如果我使用.empty(),我会得到这种行为吗? - John Arrowwood

0
我建议您使用userConfig.withFallback(ConfigFactory.load()).resolve(),而不是ConfigFactory.load().withFallback(userConfig).resolve()。对于我来说,parseResources没有改变它,结果相同(但在此测试中我不使用引用)。
这是我的测试:

application1.conf

app {
  option1 = 323
  common-option = 64
}

application2.conf

app {
  option2 = 234
  common-option = 32
}

  val conf1 = ConfigFactory.load("application1.conf")
  val conf2 = ConfigFactory.load("application2.conf")

  // 1st variant: there is no option1
  println(conf1.withValue("app", conf2.getValue("app")).resolve().getConfig("app"))
  // {"common-option":32,"option2":234}

  // 2nd variant: common option from config1
  println(conf1.withFallback(conf2).resolve().getConfig("app"))
  // {"common-option":64,"option1":323,"option2":234}

  // 3nd variant: common option from config2
  println(conf2.withFallback(conf1).resolve().getConfig("app"))
  // {"common-option":32,"option1":323,"option2":234}

文档:https://github.com/lightbend/config/blob/main/config/src/main/java/com/typesafe/config/ConfigMergeable.java#L66

     /** ... Again, for details see the spec.
     * 
     * @param other
     *            an object whose keys should be used as fallbacks, if the keys
     *            are not present in this one
     * @return a new object (or the original one, if the fallback doesn't get
     *         used)
     */
    ConfigMergeable withFallback(ConfigMergeable other);

如果我没记错的话,ConfigFactory.load() 的额外好处是可以从环境中填充配置项,这就是为什么我首先这样做的原因。 - John Arrowwood

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接