文章目录
- 一、typesafe config概述
- 1、官网
- 2、优点
- 3、JSON超集特性(HOCON)
- (1)实例
- 4、版本概述
- 二、typesafe config基本使用
- 1、API示例
- 2、更多示例
- 3、不变性
- 4、模式和验证
- 5、配置文件加载
- 6、合并配置树
- 7、处理默认值
- 8、理解Config和ConfigObject
- 9、理解ConfigFactory
一、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加载、等等。