Learn how to use the MicroProfile Config specification to externalize configuration data for an application.
You will learn how to externalise and inject both static and dynamic configuration properties from microservices using MicroProfile Config.
You’ll learn to aggregate multiple configuration sources, assign prioritisation values to these sources, merge configuration values and create custom configuration sources.
After starting the application, you will be able to access two microservices to test availability:
-
http://localhost:9080/system/properties
retrieves the information for a specific host -
http://localhost:9080/inventory/hosts
retrieves the information for a list of all previously registered hosts
To learn more about these two microservices and how you can write the MicroProfile application, see Creating a MicroProfile application.
In addition, you will be able to access a third microservice which retrieves and aggregates all of the configuration properties and sources that have been added throughout this guide. This is available at:
MicroProfile Config uses Contexts and Dependency Injection (CDI) to inject configuration property values directly into an application without requiring user code to retrieve them. The injected values are defined as static because they are set only at application startup. MicroProfile Config combines configuration values from multiple sources, each known as a ConfigSource
The API combines configuration values from multiple sources, each known as a ConfigSource. Each ConfigSource has a specified priority, defined by its ordinal value. A higher ordinal means that the values taken from this ConfigSource will override values from ConfigSources with a lower ordinal value.
MicroProfile Config has three default ConfigSources:
-
System properties has a default ordinal of 400. (e.g.
bootstrap.properties
file) -
Environment variables has a default ordinal of 300. (e.g.
server.env
file) -
The
META-INF/microprofile-config.properties
configuration property file on the classpath has a default ordinal of 100.
An optional default value can be specified using Java annotations. The optional default value applies if the application does not find configuration values in any of the ConfigSources. The priority of each ConfigSource and the optional default value is shown in the following diagram:
IMAGE
Access the local microprofile-config.properties
configuration file in the start/src/main/resources/META-INF
directory. This configuration file is the default configuration source for an application that uses MicroProfile Config.
Open the configuration file. The current value of the config_ordinal
source in the META-INF/microprofile-config.properties
file is set to 600
instead of the default ordinal of 100
. Therefore, the META-INF/microprofile-config.properties
file gets the highest priority to override any other configuration values.
link:finish/src/main/resources/META-INF/microprofile-config.properties[role=include]
Begin by enabling the MicroProfile Config feature in your pom.xml
file. This feature allows you to use the MicroProfile Config API to externalize configuration data.
Navigate to the start/pom.xml
file and add the required dependency:
link:finish/pom.xml[role=include]
The mp-config feature also needs to be added to the start/src/main/liberty/config/server.xml
file:
link:finish/src/main/liberty/config/server.xml[role=include]
Now that the MicroProfile Config feature has been enabled, navigate to the local microprofile-config.properties
configuration file in the start/src/main/resources/META-INF
directory to start enabling some static configuration. This configuration file is the default configuration source for an application that uses MicroProfile Config.
The io_openliberty_guides_port_number
property that has already been defined in this file, determines the port number of the REST service.
link:finish/src/main/resources/META-INF/microprofile-config.properties[role=include]
To use this configuration property, access the partially implemented InventoryConfig
file in the start/src/main/java/io/openliberty/guides/microprofile
directory and add the following configuration injection:
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryConfig.java[role=include]
This @Inject
annotation injects the port number directly, the injection value is static and fixed on application starting.
Add the getPortNumber()
class method. This method directly returns the value of portNumber
because it has been injected.
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryConfig.java[role=include]
Open the InventoryResource.java
file. Inject the InventoryConfig
object to modify the existing class.
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryResource.java[role=include]
Get the port number from the configuration and pass this value to the getProperties(String hostname, int port)
method in the InventoryUtil.java
to get the system properties.
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryResource.java[role=include]
Note that default config sources are static and fixed on application starting, so you cannot modify them while the server is running. However, you can externalize configuration data out of the application package so that the service updates configuration changes dynamically.
Now you have a CustomConfigSource.json
file that is located outside of your application
and peers into the pom.xml
file. Transform the data object from the JSON file to the configuration for your application.
In addition to the three default configuration sources, you can create custom configuration sources by
implementing the org.eclipse.microprofile.config.spi.ConfigSource
interface and using the java.util.ServiceLoader
mechanism.
Open the custom configuration start/src/main/java/io/openliberty/guides/config/CustomConfigSource.java
source file.
Add the following content to override the ConfigSource
interface:
link:finish/src/main/java/io/openliberty/guides/config/CustomConfigSource.java[role=include]
The setProperties()
private method reads the key value pairs from the CustomConfigSource.json
JSON file and writes the information into a map.
To register the custom configuration source, add the full class name in the start/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource
file:
link:finish/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource[role=include]
Access the partially implemented InventoryConfig.java
Java class in the start/src/main/java/io/openliberty/guides/microprofile
directory.
Add the following two configuration injections:
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryConfig.java[role=include]
The first @Inject
annotation injects the Config object, which is request scoped.
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryConfig.java[role=include]
The second @Inject
annotation injects the io_openliberty_guides_inventory_inMaintenance
configuration property, a dynamic injection that uses the Provider<>
interface, which forces the service to retrieve the inMaintenance
value just in time.
Add the isInMaintenance()
class method as shown in the following example:
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryConfig.java[role=include]
Every time that you invoke the inMaintenance.get()
method, the Provider<>
interface picks up the
latest value of the io_openliberty_guides_inventory_inMaintenance
property from configuration sources.
Open the InventoryResource.java
file. Use the inventoryConfig.isInMaintenance()
class method to determine whether the inventory service is in maintenance
or not according to the configuration. If you set the io_openliberty_guides_inventory_inMaintenance
property to true
in the configuration, the inventory service returns the message, Service is temporarily down for maintenance
.
Modify the existing class to the following code:
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryResource.java[role=include]
Configuration values are purely Strings. MicroProfile Config API has built-in converters that automatically converts configured Strings into target types such as int
, Integer
, boolean
, Boolean
, float
, Float
, double
and Double
.
Therefore, in the previous section, it is type-safe to directly set the variable type to Provider<Boolean>
:
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryConfig.java[role=include]
To convert configured Strings to an arbitrary class type, such as the Email
class type which is defined in the start/src/main/java/io/openliberty/guides/config/Email.java
source file,
add a custom converter by implementing the generic interface org.eclipse.microprofile.config.spi.Converter<T>
.
Open the start/src/main/java/io/openliberty/guides/config/CustomEmailConverter.java
file.
Add the following content to override the Converter<T>
interface:
link:finish/src/main/java/io/openliberty/guides/config/CustomEmailConverter.java[role=include]
To register the custom converter, add the full class name in the start/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.Converter
file:
link:finish/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.Converter[role=include]
To use the custom Email
converter, open the InventoryConfig.java
file, inject the io_openliberty_guides_email
property, and add the getEmail()
method:
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryConfig.java[role=include]
Open the InventoryResource.java
file. Modify the returnMessage().
link:finish/src/main/java/io/openliberty/guides/inventory/InventoryResource.java[role=include]
Open the start/src/main/java/io/openliberty/guides/common/JsonMessages.java
file. Add the returnMessage()
method.
link:finish/src/main/java/io/openliberty/guides/common/JsonMessages.java[role=include]
To see the new application in action, run the Maven liberty:start-server
command from the start
directory:
$ mvn liberty:start-server
Once the server is running, you can find the service that retrieves configuration information that is specific to this guide at the following location:
The following two microservices should be available to access initially:
At first, the config_ordinal
value of the custom configuration source is set to 500
.
A value of 500
does not override configuration values of the default microprofile-config.properties
source, which has a config_ordinal
value of 600
.
However, you can manually change the config_ordinal
value to a larger number in the CustomConfigSource.json
file.
Restart the application. Play with this application by changing configuration values for each property in the CustomConfigSource.json
file.
For example, change io_openliberty_guides_inventory_inMaintenance
from false
to true
, then try to access http://localhost:9080/inventory/hosts
again,
you can see a message that says Service is temporarily down for maintenance
.
Your changes are added dynamically, and you do not need to restart the server. Refresh the pages to see the dynamic changes.
Add the following test cases to the corresponding locations in the start/src/test/java/it/io/openliberty/guides/microprofile/ConfigurationTest.java
file:
link:finish/src/test/java/it/io/openliberty/guides/config/ConfigurationTest.java[role=include]
The testInitialServiceStatus()
test case reads the value of the io_openliberty_guides_inventory_inMaintenance
configuration property in the file META-INF/microprofile-config.properties
and checks the HTTP response of the inventory service. If the configuration value is false
, the service returns a valid response. Otherwise,
the service returns a message that says, Service is temporarily down for maintenance
.
link:finish/src/test/java/it/io/openliberty/guides/config/ConfigurationTest.java[role=include]
Because the META-INF/microprofile-config.properties
default source has the highest ordinal value of 600
in the beginning,
the testOverrideConfigProperty()
test case first checks that the http://localhost:9080/inventory/config/all
microservice contains
the io_openliberty_guides_testConfigOverwrite
test property with the DefaultSource
value, which is set by this default file.
Then, the test changes the ordinal value of the custom configuration source from 500
to 700
so that the custom configuration source becomes the highest priority. In the end, the CustomSource
value overrides the test property.
link:finish/src/test/java/it/io/openliberty/guides/config/ConfigurationTest.java[role=include]
Because the io_openliberty_guides_inventory_inMaintenance
configuration property is set to false
by default, the testPutServiceInMaintenance()
test case first checks that the inventory service is not in maintenance in the beginning. Next,
this test increases the priority of the custom configuration source and switches the value of the io_openliberty_guides_inventory_inMaintenance
configuration property
to true
. In the end, the inventory service returns a message that says, Service is temporarily down for maintenance
.
Add the test suite method:
link:finish/src/test/java/it/io/openliberty/guides/config/ConfigurationTest.java[role=include]
Reset the microprofile-config.properties
file and the CustomConfigSource.json
file to the following original values before you run tests.
Some of the test cases assume the default configuration.
link:finish/src/main/resources/META-INF/microprofile-config.properties[role=include]
{ "config_ordinal": 500,
"io_openliberty_guides_inventory_inMaintenance": false,
"io_openliberty_guides_system_inMaintenance": false,
"io_openliberty_guides_email": "admin@guides.openliberty.io",
"io_openliberty_guides_testConfigOverwrite": "CustomSource"
}
To rebuild and run the tests, navigate to the start
directory and run the mvn clean install
command
from the command line:
# Stop the server if it is still running from previous steps:
$ mvn liberty:stop-server
# Next, execute the command:
$ mvn clean install
The program might take some time to execute the tests. If the tests pass, you receive the following output:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.microprofile.ConfigurationTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.324 sec - in it.io.openliberty.guides.microprofile.ConfigurationTest
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
You just built and tested a MicroProfile application with MicroProfile Config and Open Liberty.