hoplite
hoplite是一个Kotlin库,用于以无样板方式将配置文件加载到TypeAfe类中。使用Kotlin数据类定义您的配置,在启动时, hoplite将从一个或多个配置文件中读取,将这些文件中的值映射到您的配置类中。任何丢失的值或无法转换为所需类型的值都会导致配置失败,并使用详细的错误消息。
特征
- 多种格式:以几种格式编写配置:YAML,JSON,TOML,HOCON或JAVA .props Files,甚至在同一系统中混合和匹配格式。
- 属性来源:从JVM系统属性,环境变量,JNDI或每个用户本地配置文件中可以使用每现在系统替代。
-
电池包括:对许多标准类型的支持,例如原始类型,枚举,日期,收集类型,内联类,UUID,无效类型,以及受欢迎的Kotlin第三方库类型,例如
NonEmptyList,Option和TupleX来自Arrow。 -
自定义数据类型:
Decoder接口使您可以轻松地添加对您的自定义域类型或未介绍的标准库类型的支持。 - 级联:配置文件可以堆叠。从默认文件开始,然后在顶部将新配置层层。解决配置时,值的查找落在包含定义的第一个文件中。可以用来具有默认配置文件,然后使用特定于环境的文件。
- 美丽的错误:在运行时失败,出现了精美的错误,显示出了什么出了什么问题和位置。
- 预处理程序:支持几个预处理程序,这些预处理器将用从外部配置解决的值替换占位符,例如AWS Secrets Manager,Azure KeyVault等。
- 可重新加载配置:触发配置重新加载在固定的间隔或响应外部事件(例如领事价值更改)时。
- 前缀绑定:可选地,加载配置源一次,然后将单个前缀路径绑定到独立的配置类型中。
ChangElog
请参阅此处的每个版本中的更改列表。
入门
将hoplite添加到您的构建中:
hoplite -core:<version>\’\”>
implementation \' com.sksamuel. hoplite : hoplite -core:<version> \'
您还需要包含用于使用格式的模块。
接下来定义将包含配置的数据类。您应该创建一个可以简单地命名Config或ProjectNameConfig的顶级类。然后,此类为您需要的每个配置值定义一个字段。它可以包括用于将相关配置分组的嵌套数据类。
例如,如果我们有一个需要数据库配置的项目,嵌入式HTTP服务器的配置以及一个包含我们正在运行的环境(登台,QA,生产等)的字段,那么我们可能会定义这样的类:
data class Database ( val host : String , val port : Int , val user : String , val pass : String ) data class Server ( val port : Int , val redirectUrl : String ) data class Config ( val env : String , val database : Database , val server : Server )
对于我们的登台环境,我们可能会创建一个称为application-staging.yaml YAML(或JSON等)文件。该名称无关紧要,您可以使用您想要的任何惯例。
env : staging database : host : staging.wibble.com port : 3306 user : theboss pass : 0123abcd server : port : 8080 redirectUrl : /404.html
最后,要从此文件构建Config实例,并且假设配置文件在classPath上,我们可以简单地执行:
val config = ConfigLoaderBuilder .default() .addResourceSource( \" /application-staging.yml \" ) .build() .loadConfigOrThrow< Config >()
如果配置文件中的值兼容,则将返回Config实例。否则,将抛出一个例外,其中包含错误的详细信息。
配置加载程序
正如您从“入门指南”中看到的那样, ConfigLoader是使用hoplite入口点。我们通过ConfigLoaderBuilder Builder创建此加载程序类的实例。在此构建器中,我们添加资源,配置,启用报告,添加预处理器等。
要创建一个默认的构建器,请使用ConfigLoaderBuilder.default() ,然后添加源后,调用build 。这是一个示例:
ConfigLoaderBuilder .default() .addResourceSource( \" /application-prod.yml \" ) .addResourceSource( \" /reference.json \" ) .build() .loadConfigOrThrow< MyConfig >()
ConfigLoaderBuilder上的default方法设置了建议的默认值。如果您想从一个完全空的配置构建器开始,请使用ConfigLoaderBuilder.empty() 。
有两种方法可以从配置检索填充的数据类。首先是如果无法解决配置,则提出异常。我们通过loadConfigOrThrow<T>函数来执行此操作。另一个是如果要手动处理错误,则通过loadConfig<T>函数返回ConfigResult验证单元。
在大多数情况下,当您在应用程序启动时解决配置时,基于异常的方法更好。这是因为您通常希望Config中的任何错误以中止应用程序引导程序,将错误立即转移到控制台上。
前缀结合
前缀可用于将选定的配置绑定到独立的数据类。这对于模块化配置加载很有用。例如,独立的模块或插件从一组共同的配置源加载自己的配置。
例如包含
module1 : foo : bar module2 : baz : qux
可以绑定到:
data class Module1Config ( val foo : String ) data class Module2Config ( val baz : String )
最好的方法是从ConfigLoader获得ConfigBinder ,例如:
val configBinder = ConfigLoaderBuilder .default() .addResourceSource( \" /application-prod.yml \" ) .addResourceSource( \" /reference.json \" ) .build() .configBinder() // generally a ConfigBinder will be provided via DI, and these calls will be in their own modules! val module1Config = configBinder.bindOrThrow< Module1Config >( \" module1 \" ) val module2Config = configBinder.bindOrThrow< Module2Config >( \" module2 \" )
通过这种方法,配置源只能读取和解析一次,但可以绑定到必要的多次独立数据类。
如果只需要加载一个前缀,则还可以直接向loadConfig及其变体提供prefix 。
prefix值不必仅参考root属性foo.bar的前缀将在配置ConfigLoader创建的配置树中的foo.bar节点上访问config。
美丽的错误
当确实发生错误时,如果选择抛出异常,则错误将以人为可读的方式以及尽可能多的位置信息进行格式化。不再尝试在400行配置文件中跟踪NumberFormatException 。
这是单位测试使用的测试文件的错误格式的示例。请注意,错误表示该值已从哪个文件中提取。
hoplite.json.Foo\’ because:
– \’bar\’: Required type Boolean could not be decoded from a Long (classpath:/error1.json:2:19)
– \’baz\’: Missing from config
– \’hostname\’: Type defined as not-null but null was loaded from config (classpath:/error1.json:6:18)
– \’season\’: Required a value for the Enum type com.sksamuel. hoplite .json.Season but given value was Fun (/home/user/default.json:8:18)
– \’users\’: Defined as a List but a Boolean cannot be converted to a collection (classpath:/error1.json:3:19)
– \’interval\’: Required type java.time.Duration could not be decoded from a String (classpath:/error1.json:7:26)
– \’nested\’: – Could not instantiate \’com.sksamuel. hoplite .json.Wibble\’ because:
– \’a\’: Required type java.time.LocalDateTime could not be decoded from a String (classpath:/error1.json:10:17)
– \’b\’: Unable to locate a decoder for java.time.LocalTime\”>
Error loading config because:
- Could not instantiate \'com.sksamuel. hoplite .json.Foo\' because:
- \'bar\': Required type Boolean could not be decoded from a Long (classpath:/error1.json:2:19)
- \'baz\': Missing from config
- \'hostname\': Type defined as not-null but null was loaded from config (classpath:/error1.json:6:18)
- \'season\': Required a value for the Enum type com.sksamuel. hoplite .json.Season but given value was Fun (/home/user/default.json:8:18)
- \'users\': Defined as a List but a Boolean cannot be converted to a collection (classpath:/error1.json:3:19)
- \'interval\': Required type java.time.Duration could not be decoded from a String (classpath:/error1.json:7:26)
- \'nested\': - Could not instantiate \'com.sksamuel. hoplite .json.Wibble\' because:
- \'a\': Required type java.time.LocalDateTime could not be decoded from a String (classpath:/error1.json:10:17)
- \'b\': Unable to locate a decoder for java.time.LocalTime
支持格式
hoplite支持多种格式的配置文件。如果您真的愿意,您可以混合使用和匹配格式。对于要使用的每种格式,您必须在类路径上包含适当的hoplite模块。 hoplite用来解析文件的格式由文件扩展名确定。
| 格式 | 模块 | 文件扩展 |
|---|---|---|
| JSON | hoplite -json
|
.json |
| YAML注意:YAML文件的大小有限3MB。 | hoplite -yaml
|
.yml,.yaml |
| 汤姆 | hoplite -toml |
.toml |
| Hocon | hoplite -hocon
|
.conf |
| Java属性文件 | 内置 | .props,.properties |
如果您想添加另一种格式,则可以扩展Parser并通过addParser向ConfigLoaderBuilder提供该实现的实例。
相同的功能可用于将非默认文件扩展映射到现有解析器。例如,如果您希望将您的config放在nater application.data中但以yaml格式中的config,则可以在这样的yaml解析器上注册.data:
ConfigLoaderBuilder.default().addParser(\"data\", YamlParser).build()
注意:Fatjar/Shadowjar
如果尝试在使用多个文件类型模块时构建“胖罐”,则必须使用ShadowJar插件并在Shadowjar Gradle任务中添加指令mergeServiceFiles() 。更多信息
物业来源
PropertySource接口是hoplite读取配置值的方式。
hoplite支持几种内置的属性源实现,您可以根据需要编写自己的文章。
EnvironmentVariablesPropertySource , SystemPropertiesPropertySource , UserSettingsPropertySource和XdgConfigPropertySource源将自动注册,并以该顺序为准。其他属性源可以根据需要将其传递给Config Loader Builder。
Environment VariablesPropertysource
EnvironmentVariablesPropertySource VariablesPropertySource从环境变量中读取配置。此属性源将环境变量名称映射到通过环境变量的惯用约定配置属性。 env var是惯用的大写,仅包含字母( A至Z ),数字( 0到9 )和下划线( _ )字符。
hoplite Maps env vars如下:
-
下划线是嵌套配置的分离器。例如,
TOPIC_NAME将覆盖topic父母中的属性name。 -
要将env vars绑定到数组或列表,请使用索引的后缀EG SET env vars
TOPIC_NAME_0和TOPIC_NAME_1设置name列表属性的两个值。丢失的索引被忽略,这对于在不重新恢复后续值的情况下评论值很有用。 -
要将env vars绑定到地图,键是嵌套配置EG
TOPIC_NAME_FOO的一部分,而TOPIC_NAME_BAR将为name映射属性设置“ foo”和“ bar”键。请注意,键是惯用大写规则的一个例外 – env var名称确定地图密钥的情况。
如果提供了可选的(未指定) prefix设置,则仅考虑以前缀开头的ENV VAR,并且在处理之前将前缀从Env var中剥离。
从hoplite 3开始,默认情况下将应用EnvironmentVariablesPropertySource ,可用于直接覆盖其他配置属性。对config.override.前缀。但是,可选的prefix设置仍然可以用于相同的目的。
SystemPropertiesPropertysource
SystemPropertiesPropertySource通过config.override. 。例如,使用-Dconfig.override.database.name启动JVM将覆盖database.name驻留在文件中。
USERTESTINGSPROPERTYSOURCE
UserSettingsPropertySource通过在〜/.userconfig上定义的配置文件提供配置。[ext]其中ext是受支持的格式之一。
InputStreamPropertysource
InputStreamPropertySource提供来自输入流的配置。此源需要一个指示格式的参数。例如, InputStreamPropertySource(input, \"yml\")
configfilepropertysource
来自文件或资源的配置是通过ConfigFilePropertySource的实例检索的。当我们将字符串传递到loadConfigOrThrow或loadConfig函数时,将自动添加此属性源。
在ConfigLoaderBuilder上有便利的方法可以从类Path或文件上的资源中构造ConfigFilePropertySource s。
例如,以下是等效的:
ConfigLoader ().loadConfigOrThrow< MyConfig >( \" /config.json \" )
和
ConfigLoaderBuilder .default() .addResourceSource( \" /config.json \" ) .build() .loadConfigOrThrow< MyConfig >()
第二种方法的优点是我们可以指定文件可以是可选的,例如:
ConfigLoaderBuilder .default() .addResourceSource( \" /missing.yml \" , optional = true ) .addResourceSource( \" /config.json \" ) .build() .loadConfigOrThrow< MyConfig >()
JSONPROPERTYSOURCE
要使用JSON字符串作为属性源,我们可以使用JsonPropertySource实现。例如,
ConfigLoaderBuilder .default() .addSource( JsonPropertySource ( \"\"\" { \"database\": \"localhost\", \"port\": 1234 } \"\"\" )) .build() .loadConfigOrThrow< MyConfig >()
YamlPropertysource
要使用YAML字符串作为属性源,我们可以使用YamlPropertySource实现。
ConfigLoaderBuilder .default() .addSource( YamlPropertySource ( \"\"\" database: \"localhost\" port: 1234 \"\"\" )) .build() .loadConfigOrThrow< MyConfig >()
Tomlpropertysource
要使用TOML字符串作为属性源,我们可以使用TomlPropertySource实现。
ConfigLoaderBuilder .default() .addSource( TomlPropertySource ( \"\"\" database = \"localhost\" port = 1234 \"\"\" )) .build() .loadConfigOrThrow< MyConfig >()
Propspropertysource
要使用java.util.properties对象作为属性源,我们可以使用PropsPropertySource实现。
ConfigLoaderBuilder .default() .addSource( PropsPropertySource (myProps)) .build() .loadConfigOrThrow< MyConfig >()
级联配置
hoplite具有级联或分层或后备配置的概念。这意味着您可以将多个配置文件传递给configloader。当配置分为Kotlin类中时,查找将以传递给加载程序的顺序级联或通过一个文件落入另一个文件,直到定义该密钥的第一个文件为止。
例如,如果您在yaml中有以下两个文件:
application.yaml :
elasticsearch : port : 9200 clusterName : product-search
application-prod.yaml :
elasticsearch : host : prd-elasticsearch.scv port : 8200
两者都将两者都传递给了configloader: ConfigLoader().loadConfigOrThrow<Config>(\"/application-prod.yaml\", \"/application.yaml\") ,然后将以声明文件的顺序尝试查找。因此,在这种情况下,配置将像这样解决:
elasticsearch.port = 8200 // the value in application-prod.yaml takes priority
elasticsearch.host = prd-elasticsearch.scv // only defined in application-prod.yaml
elasitcsearch.clusterName = product-search // only defined in application.yaml
让我们看看一个更复杂的例子。这次在Json。
default.json
{
\"a\" : \" alice \" ,
\"b\" : {
\"c\" : true ,
\"d\" : 123
},
\"e\" : [
{
\"x\" : 1 ,
\"y\" : true
},
{
\"x\" : 2 ,
\"y\" : false
}
],
\"f\" : \" Fall \"
}
prod.json
{
\"a\" : \" bob \" ,
\"b\" : {
\"d\" : 999
},
\"e\" : [
{
\"y\" : true
}
]
}
我们将把上述配置文件解析到这些数据类中:
enum class Season { Fall , Winter , Spring , Summer } data class Foo ( val c : Boolean , val d : Int ) data class Bar ( val x : Int? , val y : Boolean ) data class Config ( val a : String , val b : Foo , val e : List < Bar >, val f : Season )
val config = ConfigLoader .load( \" prod.json \" , \" default.json \" ) println (config)
决议规则如下:
- 两个文件中都存在“ a”,因此从第一个文件解决 – 是“ prod.json”
- 两个文件中都存在“ B”,因此也从文件中解决
- “ c”是“ b”的嵌套值,并且不存在第一个文件中,因此从第二个文件“ default.json”中解析。
- “ D”是两个文件中存在的“ b”的嵌套值,因此从第一个文件解决
- 两个文件中都存在“ E”,因此整个列表从第一个文件解决。这意味着该列表仅包含一个元素,尽管第一个文件中的列表中存在,但X还是无效的。列表不能合并。
- “ F”仅存在于第二个文件中,因此从第二个文件中解决。
严格模式
如果不使用配置值,则可以将hoplite配置为丢弃错误。这对于检测过时的配置很有用。
要启用此设置,请在配置构建器上使用.strict() 。例如:
ConfigLoaderBuilder .default() .addResourceSource( \" /config-prd.yml \" , true ) .addResourceSource( \" /config.yml \" ) .strict() .build() .loadConfig< MyConfig >()
此输出的一个例子是:
Error loading config because:
Config value \'drop_drop\' at (classpath:/snake_case.yml:0:10) was unused
Config value \'double_trouble\' at (/home/sam/.userconfig.yml:2:16) was unused
别名
如果您想重构配置类并重命名字段,但是您不想更新所有配置文件,则可以通过允许字段使用多个名称来添加迁移路径。为此,我们使用@configalias注释。
例如,使用此配置文件:
database : host : String
我们可以将其纳入以下数据类。
data class Database ( val host : String ) data class MyConfig ( val database : Database )
或者
data class Database (@ConfigAlias( \" host \" ) val hostname : String ) data class MyConfig ( val database : Database )
参数映射器
hoplite提供了一个接口ParameterMapper ,该接口允许在配置源内查找参数名称之前对其进行修改。这允许hoplite找到与确切名称不匹配的配置键。这样做的主要用例是允许使用snake_case或kebab-case名称作为配置键。
例如,给定以下配置类:
data class Database ( val instanceHostName : String )
然后,我们当然可以定义我们的配置文件(以YML为例):
database : instanceHostName : server1.prd
但是,由于hoplite会自动注册KebabCaseParamMapper和SnakeCaseParamMapper ,因此我们可以同样容易使用:
database : instance-host-name : server1.prd
或者
database : instance_host_name : server1.prd
解码器
hoplite使用Decoder接口的实例将配置文件中的原始值转换为JDK类型。在所有标准日常类型中,都有内置的解码器,例如原语,日期,列表,集合,地图,枚举,箭头类型等。完整列表如下:
| 基本JDK类型 | 转换笔记 |
|---|---|
String |
|
Long
|
|
Int
|
|
Short
|
|
Byte
|
|
Boolean
|
从以下值创建一个布尔值: \"true\" , \"t\" , \"1\" , \"yes\"映射到true和\"false\" , \"f\" , \"0\" , \"no\"映射到false
|
Double
|
|
Float
|
|
Enums
|
Java和Kotlin枚举都得到了支持。将使用Config中给出的常数值创建定义的枚举类的实例。 |
BigDecimal
|
从字符串,长,int,double或浮动转换为bigdecimal |
BigInteger
|
从长或int转换为biginteger。 |
UUID
|
用字符串创建一个java.util.UUID
|
Locale
|
从字符串中创建一个java.util.Locale
|
| Java.Time类型 | |
LocalDateTime |
|
LocalDate
|
|
LocalTime
|
|
Duration
|
在持续时间或长度以毫秒的时间内从字符串中创建Java Duration 。 |
Instant
|
从Unix Epoc以毫秒为单位创建一个Instant实例。 |
Year
|
从2007字符串中创建Year的实例 |
YearMonth |
从2007-12弦乐中创建一个YearMonth的实例 |
MonthDay |
从格式08-18的字符串中创建MonthDay的实例 |
java.util.Date |
|
| Kotlin类型 | |
Duration |
在持续时间格式或长度以毫秒的长度中创建kotlin Duration 。 |
ByteArray
|
从字符串中创建一个Kotlin ByteArray 。 |
| Java.net类型 | |
URI |
|
URL
|
|
InetAddress
|
|
| JDK IO类型 | |
File |
从字符串路径创建Java.io.file |
Path
|
从字符串路径创建Java.nio.Path |
| Kotlin Stdlib类型 | |
Pair<A,B> |
将三个阵列转换为Pair<A,B>的实例。如果数组没有两个元素,将会失败。 |
Triple<A,B,C>
|
从三个元素的数组转换为Triple<A,B,C>的实例。如果数组没有完全三个元素,将会失败。 |
kotlin.text.Regex
|
从正则兼容字符串中创建kotlin.text.Regex
|
| 收藏 | |
List<A> |
从逗号界定的数组或字符串中创建列表。 |
Set<A>
|
从逗号界定的数组或字符串中创建一个集合。 |
SortedSet<A>
|
从逗号界定的数组或字符串中创建排序集。 |
Map<K,V>
|
|
LinkedHashMap<K,V>
|
在配置中定义的订单的地图 |
| hoplite类型 | |
Masked |
将字符串包裹在掩蔽的对象中,该对象编辑ToString() |
SizeInBytes
|
返回一个sizeinbytes对象,该对象解析了诸如12MIB或9KB之类的值 |
Seconds |
将整数用Seconds对象包装,可以使用.duration()扩展方法将其转换为持续时间。 |
Minutes
|
将整数包装在Minutes对象中,可以使用.duration()扩展方法将其转换为持续时间。 |
Base64
|
将一个ByteBuffer在Base64对象中,该对象仅在输入是有效的基本64编码字符串时才转换。 |
| Javax.security.auth | |
X500Principal
|
为字符串值创建X500Principal的实例 |
KerberosPrincipal |
为字符串值创建一个KerberosPrincipal的实例 |
JMXPrincipal |
为字符串值创建JMXPrincipal的实例 |
Principal |
为字符串值创建一个BasicPrincipal实例 |
| 箭 | 需要hoplite -arrow模块 |
arrow.data.NonEmptyList<A> |
如果数组不为空,则将数组转换为非NonEmptyList<A> 。如果数组为空,则会增加错误。 |
arrow.core.Option<A>
|
一个None用于null或未定义值,并且当前值将转换为Some<A> 。 |
arrow.core.Tuple2<A,B>
|
将两个元素的数组转换为Tuple2<A,B>的实例。如果数组没有两个元素,将会失败。 |
arrow.core.Tuple3<A,B,C>
|
将三个元素的数组转换为Tuple3<A,B,C>的实例。如果数组没有完全三个元素,将会失败。 |
arrow.core.Tuple4<A,B,C,D>
|
将四个元素的数组转换为Tuple4<A,B,C,D>的实例。如果数组没有四个元素,将会失败。 |
arrow.core.Tuple5<A,B,C,D,E>
|
将五个元素的数组转换为Tuple5<A,B,C,D,E>的实例。如果阵列没有五个元素,将会失败。 |
| Hikari连接池 | 需要hoplite -hikaricp模块 |
HikariDataSource |
将嵌套配置转换为HikariDataSource 。在创建数据源时,嵌套在字段名称下的任何键将传递到HikariConfig对象。需要hoplite -hikaricp模块 |
| hadoop类型 | 需要hoplite -hdfs模块 |
org.apache.hadoop.fs.Path |
返回HDFS路径对象的实例 |
| Cronutils类型 | 需要hoplite -cronutils模块 |
com.cronutils.model.Cron |
返回cron表达式解析的实例 |
| Kotlinx DateTime类型 | 需要hoplite -datetime模块 |
kotlinx.datetime.LocalDateTime |
|
kotlinx.datetime.LocalDate
|
|
kotlinx.datetime.Instant
|
|
| AWS SDK类型 | 需要hoplite -aws模块 |
com.amazonaws.regions.Region |
|
| 千分尺类型 | 需要hoplite -micrometer-xxx模块 |
io.micrometer.statsd.DatadogConfig |
将嵌套对象转换为datadogconfig的实例 |
io.micrometer.statsd.PrometheusConfig |
将嵌套对象转换为Prometheusconfig的实例 |
io.micrometer.statsd.StatsdConfig |
将嵌套对象转换为StatsdConfig的实例 |
持续时间格式
持续时间类型支持以下格式的单元字符串(仅较低的情况),单位值和单位类型之间具有可选空间。
-
ns,nano,nanos,nanosecond,nanoseconds -
usmicrosecondsmicro,micros,microsecond -
ms,milli,millis,millisecond,milliseconds -
s,second,seconds -
m,minute,minutes -
h,hour,hours -
d,day,days
例如, 10s 3 days或12 hours 。
预处理器
hoplite支持所谓的预处理器。这些只是从基础配置文件读取的每个值时都应用的函数。预处理器能够根据该预处理器的逻辑来转换值(或返回输入-AKA身份函数)。
例如,预处理器可以选择执行环境变量替换,配置默认值,执行数据库查找或在解决配置时需要的任何其他自定义操作。
您还可以通过将函数与配置ConfigLoader程序类上的withPreprocessor一起添加自定义的预处理器,并在Preprocessor接口的实例中传递。自定义预处理器的典型用例是在数据库中查找某些值,或从Vault或Amazon参数商店等第三方秘密商店中查找一些值。
可以实现的一种方法是具有前缀,然后使用预处理器在字符串中寻找前缀,如果存在前缀,请使用字符串的其余部分作为服务的键。 PrefixProcessor抽象类通过处理节点遍历,同时将特定的处理作为读者的练习来实现这一点。
例如
database : user : root password : vault:/my/key/path
注意:您可以通过将withPreprocessingIterations在ConfigLoaderBuilder上设置为大于1的属性来反复应用预处理器。这会导致所有预处理器的循环应用。如果您希望一个预处理程序可以解决一个值,那么这可能是有用的,然后需要另一个预处理器解决。
内置预处理器
这些内置的预处理器会自动注册。
| 预处理器 | 功能 |
|---|---|
EnvVarPreprocessor |
如果定义,则将表单$ {var}的任何字符串替换为环境变量$ var。这些替换字符串可能会在其他字符串之间发生。
例如 |
SystemPropertyPreprocessor
|
如果已定义,则将表单$ {var}的任何字符串替换为system属性$ var。这些替换字符串可能会在其他字符串之间发生。
例如 |
RandomPreprocessor
|
将随机字符串插入配置。有关语法,请参见有关随机预处理器的部分。 |
PropsFilePreprocessor
|
将表单$ {key}的任何字符串替换为提供的java.util.Properties文件中的密钥值。该文件可以通过类路径上的Path或资源指定。 |
LookupPreprocessor
|
将表格{{key}}的任何字符串替换为已解析的配置中的该节点的值。换句话说,这允许从一个地方替换到另一个地方(甚至跨文件)。 |
可选的预处理器
这些预处理器必须在生效之前将其添加到ConfigBuilder之前,并需要额外的模块才能添加到构建中。
| 预处理器 | 功能 |
|---|---|
AwsSecretsManagerPreprocessor |
通过查找AWS Secrets Manager的“键”的值来替换AWSSM:// key的字符串。
该预处理器要求将 |
AzureKeyVaultPreprocessor
|
通过查找Azure键值Vault的“键”的值来替换AzureKeyVault形式的字符串://键。
该预处理器要求将 |
ParameterStorePreprocessor
|
通过从AWS Systems Manager参数存储中查找“键”的值来替换$ {SSM:key}的字符串。
该预处理器要求将 |
ConsulConfigPreprocessor
|
通过查找领事服务器的“键”值来替换表单领事的字符串://键。
该预处理器要求将 |
VaultSecretPreprocessor
|
通过查找Vault实例的“键”的值来替换表格库的字符串://键。
该预处理器要求将 |
GcpSecretManagerPreprocessor
|
通过查找Google Cloud Secret Manager实例中的值来替换表单gcpsm://projects/{projectId}/secrets/{secretName}/versions/{version:latest}的字符串。
该预处理器要求将 |
随机预处理器
随机预处理器用随机值代替占位符字符串。
| 占位符 | 生成随机值 |
|---|---|
| $ {random.int} | 随机int |
| $ {random.int(k)} | 0和k之间的正随机int |
| $ {random.int(k,j)} | K和J之间的随机int |
| $ {Random.double} | 随机双重 |
| $ {random.boolean | 随机布尔 |
| $ {Random.String(k)} | 长度为k的随机字母数字字符串 |
| $ {random.uuid} | 随机生成的类型4 UUID |
例如:
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}
蒙版值
在调试时,在启动时输出已解决的配置以供参考很常见。在这种情况下,Kotlin的数据类生成的默认toString非常有用。但是,配置通常包括敏感信息,例如密码或密钥,通常您不想在日志中出现。
为了避免在日志输出中出现敏感的字段, hoplite提供了一种内置的类型,称为Masked ,它是围绕字符串的包装器。通过将字段声明为具有此类型,该值仍将从配置文件中加载,但不会包含在生成的toString中。
例如,您可以定义这样的配置类:
data class Database(val host: String, val user: String, val password: Masked)
和相应的JSON配置:
{
\"host\" : \" localhost \" ,
\"user\" : \" root \" ,
\"password\" : \" letmein \"
}
然后,通过toString数据库配置类的输出将是Database(host=localhost, user=root, password=****)
注意:掩蔽效果仅在使用toString时才发生。如果您使用基于反射的工具(例如杰克逊)将配置挂在字符串上,则仍然可以看到基础值。在这些情况下,您需要注册自定义序列化器。对于Jackson项目, hoplite -json模块中有一个hoplite Module对象。将其注册您的Jackson Mapper,例如mapper.registerModule( hoplite Module) ,然后将Masked值输入为JSON,为“ ****”
内联类
一些开发人员包括该作者,喜欢具有强大类型包装简单值。例如, Port对象而不是int。这有助于减轻打字的开发。 Kotlin支持所谓的内联类别满足这一需求。
hoplite直接支持内联类。使用Inline类时,您无需嵌套配置密钥。
例如,给定以下配置类:
inline class Port ( val value : Int ) inline class Hostname ( val value : String ) data class Database ( val port : Port , val host : Hostname )
然后此配置文件:
port : 9200 host : localhost
我们可以直接解析:
val config = ConfigLoader ().loadConfigOrThrow< Database >( \" config.file \" ) println (config.port) // Port(9200) println (config.host) // Hostname(\"localhost\")
密封的课程
hoplite将支持密封的类,其中它能够将可用的配置密钥与其中一个实现的参数匹配。例如,让我们创建一个配置层次结构作为密封类的实现。
sealed class Database {
data class Elasticsearch ( val host : String , val port : Int , val index : String ) : Database()
data class Postgres ( val host : String , val <span cl
