MicroProfile Config API
The MicroProfile Config API can be used by applications as a single API that can retrieve configuration information from different sources.
For information about using the Liberty MicroProfile Config feature versions 1.1 and later, see the Open Liberty website
- Multiple configuration sources can be amalgamated into a single configuration and accessed with one API.
- Configuration property values can be overridden with values from configuration sources that are designated as having a higher precedence.
- Values can be stored in named properties files, system environment variables, or Java™ System properties.
ConfigSource
resources are loaded by using a JavaClassLoader
, either the application's current contextClassLoader
or a user suppliedClassLoader
.- Values can be provided by registering a user implementation of a
ConfigSource
interface. - Values can be retrieved as Strings or as typed objects of a particular Java class by using built in or custom type Converters.
ConfigSource
andConverter
implementations can be discovered by using the JavaServiceLoader
pattern.- Configuration property values, whether for primitives, standard types, or user supplied types, can be directly injected by using Java CDI (Context and Dependency Injection).
Configuration injection
The MicroProfile Config API collects the default configuration sources and configuration sources
that are loaded by Java
ServiceLoader
configsources
, and are discussed later in this topic. It is possible to use Java CDI (Contexts and Dependency Injection) to inject the
configuration object directly into an application.
@Inject
Config config;
String appName = config.getValue("APP_NAME", String.class);
It is also possible to inject a single configuration property value.
@Inject
@ConfigProperty
String PROPERTY_NAME1;
These properties are represented in raw form as Strings just like standard Java properties. The system uses the default settings for configuration sources and
obtains the name of the configuration property from the name of the classname
where
the first letter is lowercase and then appended with the variable name, and the separator is a dot.
For example, if the previous snippet is in the class that is called ClassA
, the
property name that is resolved is classA.PROPERTY_NAME1
.
@Inject
@ConfigProperty(name="PROPERTY_NAME2")
String propertyTwo;
This code snippet is to look up the mandatory property PROPERTY_NAME2 from the config sources. If the property does not exist, a DeploymentException is thrown.
configsources
, use the
defaultValue parameter to assign the default
value.@inject
@ConfigProperty(name="myName", defaultValue="Bob")
String name;
This code snippet looks up the property myName
from the configured
configsources
. If the property is not defined, the value Bob
is assigned to the variable name.Programmatic lookup of configuration
The MicroProfile Config API also supplies an interface to retrieve the configuration properties by using method calls. This retrieval can be done in two ways, an easy to use configuration provider class that uses default settings and a fully customizable configuration builder class.
The ConfigProvider class
The simplest way to use a configuration is by using a static method on the
ConfigProvider
class. This API collects the default configuration sources and
configuration sources that are loaded by the Java®
ServiceLoader
configsources
.
Config config = ConfigProvider.getConfig();
String appName = config.getValue("APP_NAME", String.class);
The ConfigBuilder class
For users that want to create configurations in a more customized way, a configuration builder API can be used to set various options before the configuration is generated. This example uses the builder pattern to build the equivalent configuration to the one in the previous example.
ConfigBuilder builder = ConfigProviderResolver.getBuilder();
builder.addDefaultSources();
Config config = builder.build();
Calling builder.addDefaultSources()
adds in the same set of default sources the
ConfigProvider
uses to build configurations. Other configuration sources can also
be added.
Configuration sources
Configuration properties can be sourced from a number of locations, including property files, and
user classes that are either registered by the application or loaded by using the Java
ServiceLoader
pattern.
Default sources
Unlike the ConfigProvider
interface, the ConfigBuilder
interface initially has an empty set of configuration property sources. Adding the default sources
has the following effects:
- Process environment variables are included in the configuration. Liberty shows host process environment variables
to the Java
System.getenv()
method and additionally adds in properties from the server's server.env file. These variables are then available to the MicroProfile Config API. - Java System Properties available by way of
System.getProperties()
are included in the configuration. Liberty adds properties from the server's bootstrap.properties and jvm.options file to the Java System Properties. - Files that are loaded from the application
ThreadContextClassLoader
classpath with aresourceName
of META-INF/microprofile-config.properties. Within these property files, properties are stored by using the same syntax that is used by standard Java Properties files. For a Liberty application, the META-INF directory location might be as a sub directory at the root of a JAR or the WEB-INF\classes\META-INF\ directory for a WAR file, or in a JAR in an EAR's lib directory, or in a server level shared library JAR. TheClassLoader
, and thus classpath, used can be altered by using theforClassLoader
method of the builder.
User-provided ConfigSources
A user class that implements org.eclipse.microprofile.config.spi.ConfigSource
can be registered with a ConfigBuilder
. In this way, this user class is then
included in later in configurations that the builder produces.
MySource source = new MySource();
builder.withSources(source);
Java ServiceLoader loading of ConfigSources
The Java ServiceLoader pattern can also be used to locate
custom configuration source objects. A user class that implements the ConfigSource
interface is loaded if its full package qualified class name is listed in a file of the form,
${CLASSPATH}/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource.
Converters
The MicroProfile Config API can also retrieve properties as Java object types with a genericized method that takes the type of the property object that is wanted. This method can work for any type that has either a built-in or user supplied converter. For instance, the code in the previous example can be written to use the built-in String converter as:
appName = config.getOptionalValue("APP_NAME", String.class).orElse("MicroDemo");
Built-in converters
The MicroProfile Config API includes built in converters for the following types:
boolean
, Boolean
, int
, Integer
,
long
, Long
, float
, Float
,
double
, Double
, Duration
,
LocalTime
, LocalDate
, LocalDateTime
,
OffsetDateTime
, OffsetTime
, Instant
, and
URL
.
Variables of any of these types can be directly injected, or retrieved by using the genericized
getValue
call. If the string value of the property can be successfully converted to
the type by using the relevant valueof
, parse
, or constructor
method by taking a single String parameter.
Custom converters
Custom converters that implement the
org.eclipse.microprofile.config.spi.Converter<T>
interface can be registered
and used in configurations by using the 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);
The withConverters
method uses reflection to determine what type the converter is
for. Java Lambda code currently does not offer specific enough
type information to the reflection APIs, so code that explicitly implements a
Converter<T>
interface is required for a custom converter.Converter priority
If multiple converters for the same type exist, the converter that is used can be controlled by
using a @Priority
annotation. This method allows for Converter implementation to be
overridden later in the application lifecycle. A converter overrides any other converter with a
lesser priority that is for the same type.
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;
}
}
The default priority for a Converter if the @Priority
annotation is not used is
100.
Java ServiceLoader support for converters
The Java ServiceLoader pattern can also be used to locate custom converters if their package qualified classnames appear in a service file of the form, ${CLASSPATH}/META-INF/services/org.eclipse.microprofile.config.spi.Converter.
Both default converters included in the MicroProfile Config API implementation, and converters
that are discovered by using the Java
ServiceLoader
pattern are available for all configurations to use.
Overriding property values
When more than one configuration source is used, the properties from all the sources are collected together and accessed as a single set by the application. Each configuration source is assigned an ordinal value. If a property appears in more than one source, then the property value from the source with the highest ordinal takes precedence and is returned to the application. Default ordinal values are:
- System Properties - 400
- Environment Variables - 300
- /META-INF/microprofile-config.properties - 100
- Custom
ConfigSource
Objects - ThegetOrdinal
result of theConfigSource
config_ordinal
property that is located in the configuration source to which it
applies.If two ConfigSources
that provide the same property have identical ordinals,
then the ConfigSources
ID is used for comparison according to the string comparison
rules.
Sources that are normally set earlier in the development lifecycle have lesser ordinals and precedence. This is to support the ability to override an existing property value later on in the application lifecycle, for example during application assembly or install.
Dynamic property values
Although a well designed microservice application maintains availability across individual application restarts, it is desirable for changes to configuration values to be available to an application without restarting it.
For versions of the mpConfig feature before version 1.4, the property values in a configuration
that are provided by registered ConfigSource
objects can be refreshed with any
updated values the ConfigSources
provide. The frequency that
ConfigSources
are consulted and any values are refreshed is controlled by the
microprofile.config.refresh.rate
Java system property. The units that are used are milliseconds
and the default value is 500
meaning that, by default,
ConfigSources
provided values feed into any Configuration they contribute to in
around half a second. Non-programmatic configuration sources such as
microprofile-config.properties files are not dynamically reread after initial
config construction.
The way that cached
values are retrieved from the MicroProfile configuration changed with the
mpConfig-1.4
feature. For more information, see the Open Liberty blog.
To enable updates in values to be seen after properties are injected, a
ConfigValue
object can be used. This has getters, for both the configuration
property value and an Optional<T>
of the configuration property value, that
return the current value each time the getter is called. For example:
@Inject
@ConfigProperty(name="propertyName3")
Provider<MyClass> propertyName3;
MyClass mc = propertyName3.get();
You can also see that the ConfigValue
class is genericized and can be used to
retrieve a property of a specific type if a suitable Converter is present.
Config caching
To aid with efficiency, a ConfigProvider
caches the Config returned by its
getConfig
method for a particular application (or module) identified by its
ClassLoader
. If the config is generated by using ConfigBuilder
,
the config object is not cached. However, the ConfigProviderResolver
, in the
org.eclipse.microprofile.config.spi package, has a
registerConfig
method that can be used to cache Config objects, and a
releaseConfig
method to release the Config object.
For more information about implementing the MicroProfile Config in Liberty, see MicroProfile Configuration project site.