MicroProfile Config API

The MicroProfile Config API can be used by applications as a single API that can retrieve configuration information from different sources.

When you use the MicroProfile Config API:
  • 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 Java ClassLoader, either the application's current context ClassLoader or a user supplied ClassLoader.
  • 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 and Converter implementations can be discovered by using the Java ServiceLoader 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.

If a property does not exist in any configured 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:

  1. 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.
  2. 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.
  3. Files that are loaded from the application ThreadContextClassLoader classpath with a resourceName 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. The ClassLoader, and thus classpath, used can be altered by using the forClassLoader 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 - The getOrdinal result of the ConfigSource
Note: The first three ordinal values that are listed can be overridden by using a 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.

Open Liberty 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.