Java配置工具:typesafe config使用文档超详解

一、typesafe config概述

1、官网

https://github.com/lightbend/config/tree/v1.4.2#essential-information

2、优点

  • 纯java实现,没有其他依赖。
  • 支持三种格式的文件:Java属性、JSON和一个对人友好的JSON超集。
  • 合并所有格式的多个文件。
  • 可以从文件、URL或类路径加载。
  • 对“嵌套”的良好支持(将配置的任何子树视为整个配置)。
  • 用户可以用Java系统属性覆盖配置,java -Dmyapp.foo.bar=10
  • 支持从application.conf等单一文件配置应用程序及其框架和库。
  • 解析持续时间和大小设置,“512k”或“10秒”。
  • 转换类型,所以如果你要求一个布尔值,值是字符串“yes”,或者你要求一个浮点数,值是一个整数,它会计算出来。
  • 基于不可变Config实例的API,用于线程安全和配置转换的简单推理。
  • 广泛的测试覆盖面。

注意!这个库仅限于配置文件。如果想从数据库或其他地方加载config,需要编写一些自定义代码。该库对合并配置有很好的支持,所以如果从一个定制的源构建一个,很容易将它合并进来。

3、JSON超集特性(HOCON)

JSON超集被称为“人类优化的配置对象符号”或HOCON,文件使用后缀.conf。处理完一个.conf文件,结果总是一个JSON树。

  • 注释:#或者//
  • 允许省略{}围绕根对象
  • =等同于:
  • 对象之前允许省略=或者: 比如:foo { a : 42 }
  • 只要有换行符,就允许省略逗号
  • 在对象和数组的最后一个元素后允许尾随逗号
  • 允许键和值使用不带引号的字符串
  • 未加引号的键可以对嵌套对象使用点符号,foo.bar=42表示foo { bar : 42 }
  • 允许重复的密钥;较晚的值会覆盖较早的值,但两个对象递归合并的对象值键除外。
  • include特性将另一个文件中的根对象合并到当前对象中,因此foo { include "bar.json" }bar.json中的键合并到对象foo
  • 不带文件扩展名的include包括以下任何内容:.conf, .json, .properties
  • 您可以包含文件、URL或类路径资源。使用include url("http://example.com")或者file()或者classpath()语法来强制类型,或者只使用include "whatever"让库做你可能想做的事(注意:url()/file()/classpath()语法在Play/Akka 2.0中不支持,仅在更高版本中支持。)
  • 替换:foo : ${a.b}将键foo设置为与a对象中的b字段相同的值
  • 替换连接成不带引号的字符串:foo : the quick ${colors.fox} jumped
  • 如果替换在配置本身中没有解决,那么它们会退回到环境变量,所以${HOME}会像您预期的那样工作。此外,大多数配置都合并了系统属性,因此您可以使用${user.home}。
  • 替换如果转换失败,替换通常会导致错误,但是有一个语法${?a.b}允许配置缺失。
  • +=向数组追加元素的语法,path += "/bin"
  • Python或Scala中带三重引号的多行字符串

(1)实例

// 1. json
{
    "foo" : {
        "bar" : 10,
        "baz" : 12
    }
}

// 2.删除根括号:
"foo" : {
    "bar" : 10,
    "baz" : 12
}
// 3.删除引号:
foo : {
    bar : 10,
    baz : 12
}
// 4.使用 = 并且省略 :
foo {
    bar = 10,
    baz = 12
}

// 5.删除逗号:
foo {
    bar = 10
    baz = 12
}
// 6.对无引号的键使用点符号:
foo.bar=10
foo.baz=12
// 将点符号字段放在一行中:
foo.bar=10, foo.baz=12

// 7.变量替换
standard-timeout = 10ms
foo.timeout = ${standard-timeout}
bar.timeout = ${standard-timeout}

// 8.继承
foo = { a : 42, c : 5 }
foo = { b : 43, c : 6 }
// 等同于:
foo = { a : 42, b : 43, c : 6 }
// 可以利用这一点进行“继承”:
data-center-generic = { cluster-size = 6 }
data-center-east = ${data-center-generic}
data-center-east = { name = "east" }
data-center-west = ${data-center-generic}
data-center-west = { name = "west", cluster-size = 8 }
// 使用include语句,您也可以将它分割到多个文件中。
// 如果您将两个对象放在一起(第一个对象的右括号与第二个对象的左括号在同一行),它们将被合并,因此编写上述“继承”示例的一种更简短的方式是:
data-center-generic = { cluster-size = 6 }
data-center-east = ${data-center-generic} { name = "east" }
data-center-west = ${data-center-generic} { name = "west", cluster-size = 8 }

// 9.可选的系统或环境变量覆盖 带有${?foo}如果没有找到替代,替代值就会消失
// 使用JVM参数-Dconfig.override_with_env_vars=true 即使没有指定显式替换,也可以使用环境变量覆盖任何配置值。
// 环境变量值将覆盖任何预先存在的值以及作为Java属性提供的任何值。
basedir = "/whatever/whatever"
basedir = ${?FORCED_BASEDIR}

// 这个数组包含一个或两个值
path = [ "a", ${?OPTIONAL_A} ]

// 10.在配置文件外设置数组值
// 从java属性或环境变量设置数组项的值需要在数组中为该值指定索引。因此,在HOCON中,您可以将多个值设置到一个数组中或追加到一个数组中:
## HOCON
items = ["a", "b"]
items += "c"
// 使用java属性,您可以指定确切的位置:
-Ditems.0="a" -Ditems.1="b"
// 以及环境变量:
export CONFIG_FORCE_items_0=a
export CONFIG_FORCE_items_1=b

// 11.带引号或不带引号的字符串当然也可以用替换来连接:注意:${}语法必须在引号之外!
tasks-url : ${base-url}/tasks
tasks-url : ${base-url}"tasks:colon-must-be-quoted"
// 串联可以引用同一字段的早期值:
path : "/bin"
path : ${path}":/usr/bin"
// 数组也可以连接起来:
path : [ "/bin" ]
path : ${path} [ "/usr/bin" ]
// 追加到数组有一个简写:
// equivalent to: path = ${?path} [ "/usr/bin" ]
path += "/usr/bin"

// 以下是等价的:
data-center-generic = { cluster-size = 6 }
data-center-east = ${data-center-generic}
data-center-east = { name = "east" }
// 与以上是等价的
data-center-generic = { cluster-size = 6 }
data-center-east = ${data-center-generic} { name = "east" }

4、版本概述

版本1.2.1和更早的版本支持Java 6,而更新的版本(1.3.0和更高版本)支持Java 8。

引包:

<dependency>
    <groupId>com.typesafe</groupId>
    <artifactId>config</artifactId>
    <version>1.4.2</version>
</dependency>

或者直接下载依赖jar包:https://repo1.maven.org/maven2/com/typesafe/config/

更新日志:https://github.com/lightbend/config/blob/main/NEWS.md

.conf配置文件的格式:https://github.com/lightbend/config/blob/main/HOCON.md

二、typesafe config基本使用

1、API示例

import com.typesafe.config.ConfigFactory
// 加载配置
Config conf = ConfigFactory.load();
int bar1 = conf.getInt("foo.bar"); // 获取int值
Config foo = conf.getConfig("foo"); // 获取config
int bar2 = foo.getInt("bar"); // 从config获取int值

2、更多示例

在项目的examples/目录下有更多示例:https://github.com/lightbend/config/tree/main/examples

简而言之,如示例所示:

  • 库应该使用应用程序提供的Config 实例(如果有),如果没有提供特殊Config ,则使用ConfigFactory.load()。库应该将它们的默认值放在类路径的reference.conf中。
  • 可以按照他们想要的方式创建配置(ConfigFactory.load()是最简单的),然后将它提供给他们的库。可以使用ConfigFactory中的解析器方法创建Config,或者使用ConfigValueFactory中的方法从您喜欢的任何文件格式或数据源构建配置。

3、不变性

对象是不可变的,所以Config上转换配置的方法返回一个新的Config。其他类型如ConfigParseOptions、ConfigResolveOptions、ConfigObject等。也是不可改变的。

在API中可以查看更多:https://lightbend.github.io/config/latest/api/

4、模式和验证

没有模式语言或类似的东西。但是,建议使用两种工具:

  • 使用checkValid()方法
  • 通过设置类访问您的配置,每个设置都有一个字段,并在启动时实例化它(如果任何设置缺失,立即抛出异常)

在Scala中,设置类可能看起来像:

class Settings(config: Config) {

    // validate vs. reference.conf
    config.checkValid(ConfigFactory.defaultReference(), "simple-lib")

    // non-lazy fields, we want all exceptions at construct time
    val foo = config.getString("simple-lib.foo")
    val bar = config.getInt("simple-lib.bar")
}

5、配置文件加载

便利的方法ConfigFactory.load()加载以下内容(首先列出的优先级较高):
1、系统属性
2、application.conf (类路径上具有此名称的所有资源)
3、application.json (类路径上具有此名称的所有资源)
4、application.properties (类路径上具有此名称的所有资源)
5、reference.conf (类路径上具有此名称的所有资源)

可以使用ConfigFactory.load("myapp ")来加载他们自己的myapp.conf。

可以使用命令行-Dconfig.file=path/to/config-file来加载配置文件:
1、config.resource:指定资源名称,而不是基本名称,即application.conf而不是application。
2、config.file:指定了文件系统路径,同样,它应该包括扩展名,而不是基本名称。
3、config.url:指定一个URL。

这些系统属性指定了应用程序的替换。{conf,json,properties},不是加法。它们仅影响使用默认ConfigFactory.load()配置的应用程序。在替换配置文件中,可以使用include“application”来包含原来的默认配置文件;在include语句之后,您可以继续覆盖某些设置。

如果在程序内部动态设置config.resource、config.file或config.url(例如使用System.setProperty()),请注意ConfigFactory有一些内部缓存,可能看不到系统属性的新值。使用ConfigFactory.invalidateCaches()强制重新加载系统属性。

关于解决reference.conf和application.conf中的替换的说明:
替换语法${foo.bar}将被解析两次。首先,合并所有reference.conf文件,然后解析结果。第二,所有的application.conf都在未解析的reference.conf之上,其结果再次被解析。
这意味着reference.conf堆栈必须是独立的;您不能让application.conf提供未定义的值${ foo . bar}。但是,只要reference.conf本身也定义了该变量,就可以覆盖reference.conf引用的变量。

6、合并配置树

任何两个配置对象都可以用一个叫做withFallback的关联操作合并,比如merged = firstConfig.withFallback(secondConfig)

withFallback操作用于在库中合并同一文件中的重复键,以及合并多个文件。ConfigFactory.load()使用它在reference.conf上的application.conf上堆叠系统属性。

您还可以使用withFallback合并一些硬编码的值,或者将一个子树“提升”到配置的根;假设你有这样的东西:

foo=42
dev.foo=57
prod.foo=10

那么您可以编写如下代码:

Config devConfig = originalConfig
                     .getConfig("dev")
                     .withFallback(originalConfig)

有很多方法可以使用withFallback。

7、处理默认值

许多其他配置API允许您为getter方法提供一个默认值,如下所示:

boolean getBoolean(String path, boolean fallback)

如果没有该配置的话,通过get方法会抛异常。

8、理解Config和ConfigObject

一个Config将等同于JSON的数据结构视为从路径到值的一级映射。所以如果你的JSON看起来像这样:

  "foo" : {
    "bar" : 42
    "baz" : 43
  }

使用Config接口,您可以编写conf.getInt(“foo.bar”)。这foo.bar字符串被称为路径表达式 (HOCON.md有这些表达式的语法细节)。迭代这个Config,您将得到两个条目;“foo.bar” : 42和"foo.baz" : 43。当迭代Config你不会找到嵌套的Config(因为一切都变得扁平了)。

当把JSON树看作Config, null值被视为缺失。迭代一个Config将跳过null价值观。

你也可以看看Config就像大多数JSON APIs一样,通过配置对象界面。这个接口表示JSON树中的一个对象节点。ConfigObject实例出现在多层树中,键没有任何语法(它们只是字符串,不是路径表达式)。作为一个ConfigObject,您将得到一个条目"foo" : { “bar” : 42, “baz” : 43 },其中值在"foo"是另一个嵌套ConfigObject.

在ConfigObject里, null值是可见的(不同于缺失值),就像在JSON中一样。

ConfigObject是的子类型配置值,其中其他子类型是其他JSON类型(列表、字符串、数字、布尔、空)。

Config和ConfigObject是查看同一内部数据结构的两种方式,您可以在它们之间自由转换Config.root()和ConfigObject.toConfig().

从版本1.3.0开始,如果您有一个遵循JavaBean约定的Java对象(零参数构造函数、getters和setters ),您可以从Config.

使用ConfigBeanFactory.create(config.getConfig(“subtree-that-matches-bean”), MyBean.class)来做这个。

从创建beanConfig自动验证配置是否匹配bean的隐含模式。Bean字段可以是基本类型、类型化列表,如List<Integer>, java.time.Duration, ConfigMemorySize,甚至是生的Config, ConfigObject,或者ConfigValue(如果您想手动处理特定值)。

9、理解ConfigFactory

包含用于创建 Config 实例的静态方法。

包括从文件加载Config、从字符串加载Config、从Map加载、等等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃了也弱了。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值