GraceJansen / draft-guide-microprofile-config

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Configuring Microservices using MicroProfile Config

Learn how to use the MicroProfile Config specification to externalize configuration data for an application.

What you’ll learn

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:

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:

Background Concepts

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]

Injecting configuration into the application

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]

Creating custom configuration sources

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]

Enabling dynamic configuration injection

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]

Adding custom converters

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]

Starting the application

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.

Testing the application

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]

Running the tests

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

Great work! You’re done!

You just built and tested a MicroProfile application with MicroProfile Config and Open Liberty.

About

License:Other


Languages

Language:Java 90.6%Language:HTML 9.4%