![[17.0.0.3 and later]](../ng_v17003plus.gif)
MicroProfile Config API
应用程序可以使用 MicroProfile Config API 作为单个可从不同源中检索配置信息的 API。
- 可以将多个配置源合并为单个配置,并通过一个 API 来访问。
- 可以使用设计为具有更高优先顺序的配置源中的值来覆盖配置属性值。
- 可以将值存储在所指定的属性文件、系统环境变量或者 Java™ 系统属性中。
- 使用 Java ClassLoader(应用程序的当前上下文 ClassLoader 或者用户提供的 ClassLoader)来装入 ConfigSource 资源。
- 可以通过注册 ConfigSource 接口的用户实现来提供值。
- 可以使用内置转换器或者定制类型的转换器将值作为字符串或者特定 Java 类的类型化对象来检索。
- 可以使用 Java ServiceLoader 模式来发现 ConfigSource 和 Converter 实现。
- 可以使用 Java CDI(上下文和依赖性注入)直接注入配置属性值(无论是基本类型、标准类型还是用户提供的类型的配置属性值)。
配置注入
MicroProfile Config API 将收集缺省配置源以及由 Java ServiceLoader configsources 装入的配置源,本主题后面部分对这些配置源进行了讨论。可以使用 Java CDI(上下文和依赖性注入)将配置对象直接注入应用程序中。
@Inject
Config config;
String appName = config.getValue("APP_NAME", String.class);
还可以注入单个配置属性值。
@Inject
@ConfigProperty
String PROPERTY_NAME1;
正如标准 Java 属性一样,这些属性以字符串形式的原始格式表示。系统使用配置源的缺省设置,从 classname 的名称获得配置属性的名称,其中,第一个字母为小写,然后附加变量名称,分隔符为句点。例如,如果前一片段位于称为 ClassA 的类中,那么解析后的属性名称为 classA.PROPERTY_NAME1。
@Inject
@ConfigProperty(name="PROPERTY_NAME2")
String propertyTwo;
此代码段用于从配置源中查找强制属性 PROPERTY_NAME2。如果该属性不存在,那么会抛出 DeploymentException。
@inject
@ConfigProperty(name="myName", defaultValue="Bob")
String name;
此代码段从所配置的 configsources 中查找 myName 属性。如果未定义该属性,那么会为变量 name 指定值 Bob。配置的程序化查找
MicroProfile Config API 还提供了一个接口,用于通过使用方法调用来检索配置属性。可以采用两种方式来完成此检索,一种是易于使用的使用缺省设置的配置提供程序类,一种是完全可定制的配置构建器类。
ConfigProvider 类
使用配置的最简单方式是通过对 ConfigProvider 类使用静态方法来使用配置。此 API 将收集缺省配置源以及由 Java® ServiceLoader configsources 装入的配置源。
Config config = ConfigProvider.getConfig();
String appName = config.getValue("APP_NAME", String.class);
ConfigBuilder 类
对于想要以更加定制化的方式来创建配置的用户,在生成配置之前,可以使用配置构建器 API 来设置各种选项。此示例使用构建器模式将等价配置构建为前一个示例中的配置。
ConfigBuilder builder = ConfigProviderResolver.getBuilder();
builder.addDefaultSources();
Config config = builder.build();
调用 builder.addDefaultSources() 将添加 ConfigProvider 用来构建配置的同一组缺省源。也可以添加其他配置源。
配置源
配置属性可以来源于许多位置,其中包括属性文件以及由应用程序注册的用户类或者通过使用 Java ServiceLoader 模式装入的用户类。
缺省源
与 ConfigProvider 接口不同,ConfigBuilder 接口最初只有一组空的配置属性源。添加缺省源具有下列影响:
- 进程环境变量包括在配置中。Liberty 向 Java System.getenv() 方法显示主机进程环境变量,此外还会添加来自服务器 server.env 文件的属性。这些变量随后可供 MicroProfile Config API 使用。
- 通过 System.getProperties() 获得的 Java 系统属性也包括在配置中。Liberty 将服务器的 bootstrap.properties 和 jvm.options 文件中的属性添加至 Java 系统属性。
- 从应用程序 ThreadContextClassLoader 类路径装入的具有 resourceName META-INF/microprofile-config.properties 的文件。在这些属性文件中,使用标准 Java 属性文件所使用的相同语法来存储属性。对于 Liberty 应用程序,META-INF 目录位置可能是 JAR 的根目录下的子目录,或者是 WAR 文件的 WEB-INF\classes\META-INF\ 目录,或者位于 EAR 的 lib 目录下的 JAR 中,或者位于服务器级别共享库 JAR 中。可以使用构建器的 forClassLoader 方法来改变所使用的 ClassLoader,从而改变类路径。
用户提供的 ConfigSource
可以向 ConfigBuilder 注册用于实现 org.eclipse.microprofile.config.spi.ConfigSource 的用户类。这样,此用户类以后将包括在构建器生成的配置中。
MySource source = new MySource();
builder.withSources(source);
通过 Java ServiceLoader 装入 ConfigSource
还可以使用 Java ServiceLoader 模式来查找定制配置源对象。对于用于实现 ConfigSource 接口的用户类,如果它的完整程序包限定类名列示在格式为 ${CLASSPATH}/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource 的文件中,那么会装入该用户类。
转换器
MicroProfile Config API 还可以将属性作为 Java 对象类型来检索,这些 Java 对象类型具有采用所需属性对象的类型的类属化方法。此方法可以用于任何具有内置转换器或用户提供的转换器的类型。例如,可以将前一个示例中的代码编写为使用内置的字符串转换器:
appName = config.getOptionalValue("APP_NAME", String.class).orElse("MicroDemo");
内置转换器
MicroProfile Config API 包括下列类型的内置转换器:boolean、Boolean、int、Integer、long、Long、float、Float、double、Double、Duration、LocalTime、LocalDate、LocalDateTime、OffsetDateTime、OffsetTime、Instant 和 URL。
如果可以使用相关 valueof、parse 或构造方法并采用单个字符串参数将属性的字符串值成功转换为该类型,那么可以直接注入或者使用类属化 getValue 调用来检索任何这些类型的变量。
定制转换器
对于用于实现 org.eclipse.microprofile.config.spi.Converter<T> 接口的定制转换器,可以使用 ConfigBuilder API 在配置中注册和使用这些转换器。
ConfigBuilder builder = ConfigProviderResolver.getBuilder();
builder.addDefaultSources();
Converter<CustomProperty> converter = new MyConverter();
builder.withConverters(converter);
Config config = builder.build();
Optional<CustomProperty> opt = config.getOptionalValue("PROPOBJ", CustomProperty.class);
withConverters 方法使用反射来确定转换器属于哪种类型。Java Lambda 代码当前未向反射 API 提供足够的特定类型信息,因此,定制转换器需要用于显式实现 Converter<T> 接口的代码。转换器优先级
如果存在同一类型的多个转换器,那么可以使用 @Priority 注释来控制所使用的转换器。此方法允许稍后在应用程序生命周期中覆盖转换器实现。转换器将覆盖同一类型的具有较低优先级的任何其他转换器。
import javax.annotation.Priority;
import org.eclipse.microprofile.config.spi.Converter;
@Priority(200)
publicclass StringPrefixConverter implements Converter<String> {
@Override
public String convert(String value) throws IllegalArgumentException {
return"Converted:" + value;
}
}
如果未使用 @Priority 注释,那么转换器的缺省优先级为 100。
转换器的 Java ServiceLoader 支持
如果定制转换器的程序包限定类名显示在 ${CLASSPATH}/META-INF/services/org.eclipse.microprofile.config.spi.Converter 格式的服务文件中,那么还可以使用 Java ServiceLoader 模式来查找这些定制转换器。
MicroProfile Config API 实现中包括的缺省转换器以及使用 Java ServiceLoader 模式发现的转换器都可供所有配置使用。
覆盖属性值
当使用多个配置源时,来自所有源的属性将收集在一起,并由应用程序作为单个集合来访问。为每个配置源都指定了序数值。如果属性显示在多个源中,那么该源中具有最高序数的属性值将优先,并返回给应用程序。缺省序数值为:
- 系统属性 - 400
- 环境变量 - 300
- /META-INF/microprofile-config.properties - 100
- 定制 ConfigSource 对象 - ConfigSource 的 getOrdinal 结果
如果用于提供同一属性的两个 ConfigSources 具有完全相同的序数,那么会使用 ConfigSources 标识按照字符串比较规则进行比较。
通常在开发生命周期中较早设置的源将具有较低的序数和优先顺序。这是为了支持稍后在应用程序生命周期中(例如,在应用程序组装或安装期间)能够覆盖现有属性值。
动态属性值
尽管良好设计的微服务应用程序在各个应用程序重新启动期间将保持可用性,但最好是对配置值的更改可用于应用程序,而不用重新启动该应用程序。可以使用 ConfigSources 所提供的任何已更新的值来刷新配置中由已注册的 ConfigSource 对象提供的属性值。查询 ConfigSources 以及刷新任何值的频率由 Java 系统属性 microprofile.config.refresh.rate 控制。所使用的单位为毫秒,并且缺省值为 500,这表示在缺省情况下,ConfigSources 所提供的值大约半秒就会进入它们所添加至的任何配置中。
在构造初始配置之后,不会动态重新读取非程序化配置源(例如,microprofile-config.properties 文件)。
为了能够在注入属性之后查看值的更新,可以使用 ConfigValue 对象。这对于配置属性值以及配置属性值的 Optional<T> 都具有 getter 方法,每次调用 getter 方法时都将返回当前值。例如:
@Inject
@ConfigProperty(name="propertyName3")
Provider<MyClass> propertyName3;
MyClass mc = propertyName3.get();
您还可以查看 ConfigValue 类已类属化,如果提供了合适的转换器,那么可以使用该类来检索特定类型的属性。
配置高速缓存
为了帮助提高效率,ConfigProvider 将高速缓存由其 ClassLoader 标识的特定应用程序(或模块)的 getConfig 方法所返回的配置。如果是使用 ConfigBuilder 生成配置,那么不会高速缓存配置对象。但是,org.eclipse.microprofile.config.spi 包中的 ConfigProviderResolver 具有 registerConfig 方法(可用来高速缓存配置对象)和 releaseConfig 方法(用来释放配置对象)。
有关在 Liberty 中实现 MicroProfile 配置的更多信息,请参阅 MicroProfile 配置项目站点。