Separating configuration from code in microservices

duration 25 minutes
Interactive Interactive

Learn how to perform static configuration injection using MicroProfile Config.

What you'll learn

Explore how to inject configuration data into a microservice without repackaging the application each time the underlying runtime environment changes. MicroProfile makes building configurable microservices easy with its MicroProfile Config feature. Application configuration properties from multiple sources are combined into a single set of configuration properties and accessed from a single API by your application.

Using the MicroProfile Config API, the sample application illustrates how a configuration property can be assigned a value in multiple configuration sources. Each source is assigned a priority. The value from the source with the highest priority takes precedence over that from a lower priority. This method allows code to run unchanged under different configurations for prototyping, development, test, quality assurance, staging, and production environments since an existing configuration value can easily be overridden as the need arises.

When you arrive at the section about the Default ConfigSources playground, you can create your own properties and update the configuration sources with values or change the source's priority. A chart will show you which value the property is assigned.

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.

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 5 default ConfigSources:

  • All META-INF/microprofile-config.properties found on the class path (default ordinal = 100).
  • Environment variables (default ordinal = 300).
  • System properties (default ordinal = 400).
  • Defined as a variable element in the Liberty server.xml file (default ordinal = 500).
  • Defined as an appProperties property element in the Liberty server.xml file (default ordinal = 600).

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:

Ordinal Priorities

Example: DevOps pipeline

Imagine that you're developing and deploying a DisplayCarTypes microservice so that you can display the types of cars that are currently available for purchase from your business. This microservice has a dependency on another microservice called ObtainCarTypes, which provides the currently available list. As you develop your DisplayCarTypes microservice, you need to ensure that it works correctly when it interacts with the ObtainCarTypes microservice. For stability and security reasons, you don't want to test against the production version of ObtainCarTypes during the development pipeline. Instead, you run six instances of the ObtainCarTypes microservice, one for each stage of the devOps pipeline as shown in the following diagram:

DisplayCarTypes microservice can connect to one of the ObtainCarTypes instances: Development on port 9080, Test on port 9081, Quality Assurance on port 9082, Production on port 9083

As you progress through this guide, you will set a configuration property for the port value to specify which of the six ObtainCarTypes instances the DisplayCarTypes microservice should connect to.

Enabling MicroProfile Config in Open Liberty

Begin by enabling the MicroProfile Config 1.3 feature in the server.xml file of the Open Liberty server. This feature allows you to use the MicroProfile Config API to externalize configuration data.

In the editor, add the following element declaration to the featureManager element that is in the server.xml file.
Copied to clipboard
<feature>mpConfig-1.4</feature>

Alternatively, click Add.
Then, click Run on the editor menu pane.

Injecting configuration through @ConfigProperty annotation

After you modify your server.xml file to include the mpConfig feature, inject a single configuration property value directly into your code with the @Inject and the @ConfigProperty annotations. The injected value is static and does not change after the application starts.

You can specify a value in the runtime environment for mandatory configuration properties. Properties are mandatory when the annotation does not specify an optional default value. When the mandatory configuration property value is not found in any of the ConfigSources, a NoSuchElementException is thrown during application startup.

To inject a mandatory port configuration property into the code, add the following @Inject and @ConfigProperty annotations to line 9 before declaring the private int port.
Copied to clipboard
@Inject @ConfigProperty(name="port")

Alternatively, click Add.
Then, click Run on the editor menu pane to see the exception occur.

Providing optional default values

You can specify a default value for a configuration property using the defaultValue parameter in the @ConfigProperty annotation. This value is used when a value is not specified in any MicroProfile Config configuration source.

Change the @ConfigProperty annotation on line 9 to the following code.
Copied to clipboard
@Inject @ConfigProperty(name="port", defaultValue="9080")

Alternatively, click Change.
Then, click Run on the editor menu pane.
Click Refresh in the browser. The prototype port (9080) of the ObtainCarTypes microservice returns the car type values A, B, C and D.

Configuring with the properties file

You can provide the /META-INF/microprofile-config.properties file as part of your packaged application. The /META-INF/microprofile-config.properties file may be created in multiple locations, but you must specify these file locations in your class path. Do not specify the same configuration property in multiple /META-INF/microprofile-config.properties files that have the same ordinal value, or the application returns an indeterminate property value.

The properties file contains settings with a default ordinal of 100, which overrides the injected default values with the same key so the port property value in the microprofile-config.properties file is used.

In /META-INF/microprofile-config.properties, add the following on line 1.
Copied to clipboard
port=9081

Alternatively, click Add.
Then, click Run on the editor menu pane.
Click Refresh in the browser to see that the port value in the /META-INF/microprofile-config.properties file is used. The development port (9081) of the ObtainCarTypes microservice returns the values carA and carB.

Configuring with an environment variable

In Open Liberty, you can use server.env files at the installation and server levels to specify environment variables. The installation level file is located at ${wlp.install.dir}/etc/server.env, and the server level file is located at ${server.config.dir}/server.env. If both files exist, the contents of the two files are merged. If the same environment variable is in both files, the value in the server level file takes precedence over the value in the installation level file.

Environment variables can also be set using the command line.

Some operating systems impose character restrictions on the name of an environment variable. For example, Linux environments do not support full stops (.) in environment variable names so you can not have property names like user.name in server.env. To set a value for a config property that has a name containing disallowed characters from an environment variable, this configsource maps config property names to environment variable names using the following rules and the first match is returned:

  • An exact match
  • An environment variable name in which all characters that are not alphanumeric or the underscore (_) character are replaced with an underscore character (eg user_name)
  • An environment variable name in which all characters that are not alphanumeric or the underscore (_) character are replaced with an underscore character and the name is converted to upper case (eg USER_NAME).

Use the ${server.config.dir}/server.env file to configure the port environment variable. The server.env file contains the environment settings with a default ordinal value of 300 which is higher than the default ordinal value of 100 for the /META-INF/microprofile-config.properties file. Thus, the port property value in server.env is used.

In server.env, add the following on line 1.
Copied to clipboard
port=9082

Alternatively, click Add.
Then, click Run on the editor menu pane to save the file and restart the server.
Click Refresh in the browser to see that the port value in the server.env file is used. The test port (9082) of the ObtainCarTypes microservice returns the values typeA, typeB, and typeC.

Configuring with a system property

Configuration variables can be retrieved from the Java system properties, which have a default ordinal of 400. Open Liberty adds properties from the server’s bootstrap.properties and jvm.options files to the Java system properties. You can create and configure the jvm.options file in multiple locations within your Open Liberty installation directory.

The following list shows the different locations where Open Liberty checks for jvm.options files:

  1. ${wlp.install.dir}/usr/shared/jvm.options
  2. ${server.config.dir}/configDropins/defaults/jvm.options
  3. ${server.config.dir}/jvm.options
  4. ${server.config.dir}/configDropins/overrides/jvm.options

The contents of these files are merged. The latter files take precedence in the case of duplicate properties. If none of these files are present, then the ${wlp.install.dir}/etc/jvm.options file is used. If a property exists in both bootstrap.properties and jvm.options, then the value from jvm.options takes precedence.

In this example, use the ${server.config.dir}/bootstrap.properties file to configure the port system property.

Add the following port value on line 1 of bootstrap.properties.
Copied to clipboard
port=9083

Alternatively, click Add.
Then, click Run on the editor menu pane to save the file and restart the server.
Click Refresh in the browser to see that the port value in the bootstrap.properties file is used. The quality assurance port (9083) of the ObtainCarTypes microservice returns values SUV, Crossover, Coupe, and Truck.

Configuring as a variable element in server.xml

With the Open Liberty implementation of MicroProfile Config 1.3 you can define configuration values as a variable in the Liberty server's server.xml configuration file. Including a variable element in the server.xml file assigns a value to the configuration entity that may be accessed by any application running on the server.

Properties declared as variable elements in the Liberty server.xml file have an ordinal value of 500. They override configuration values from ConfigSources with lower ordinal values. If duplicate properties exist in the server.xml file, the last value specified is used by MicroProfile Config.

Specify the following port value as a variable element on line 10 of the server.xml file.
Copied to clipboard
<variable name="port" value="9084"/>

Alternatively, click Add.
Then, click Run on the editor menu pane to save the file and restart the server.
Click Refresh in the browser to see that the port value specified as a variable element in the server.xml file is used. The staging port (9084) of the ObtainCarTypes microservice returns values SUV, Crossover, Coupe, Truck, and Convertible.

Configuring as an appProperties element scoped by application

You can also define a configuration value as an appProperties property element in the Liberty server's server.xml configuration file. This assigns a value to the configuration property that may be accessed by the specified application. The appProperties element can be specified in either an application or a webApplication element.

Properties defined in appProperties elements in the Liberty server.xml file have an ordinal value of 600. If duplicate property elements exist, the last value specified will be used by MicroProfile Config.

Specify the following port value as an appProperties property element on line 13 of the server.xml file.
Copied to clipboard
<appProperties> <property name="port" value="9085"/> </appProperties>

Alternatively, click Add.
Then, click Run on the editor menu pane to save the file and restart the server.
Click Refresh in the browser to see that the port value specified as an appProperties property element in the server.xml file is used. The production port (9085) of the ObtainCarTypes microservice returns values SUV, Crossover, Coupe, Truck, Convertible, and Van.

Changing the ordinal of a ConfigSource

You can override the default ordinal value of a ConfigSource by adding the config_ordinal property to your configuration source file. The configuration source with the highest ordinal value takes precedence.

When updating the default config ordinal value in the server.xml config source, the value is added just like any other variable or appProperties element. For example, <variable name="config_ordinal" value="875" />. Otherwise, in the other ConfigSources, set config_ordinal as a property.

Adding config_ordinal to /META-INF/microprofile-config.properties with a value of 700 increases its ordinal value. The port value from /META-INF/microprofile-config.properties now overrides the port value from the appProperties property element in the Liberty server.xml file, which has a default ordinal of 600.

In /META-INF/microprofile-config.properties file, add the following on line 2.
Copied to clipboard
config_ordinal=700

Alternatively, click Add.
Then, click Run on the editor menu pane.
Click Refresh in the browser to see that the port value in the /META-INF/microprofile-config.properties file is used instead of the one defined in the server.xml file as an appProperties property element. The Development port (9081) of the ObtainCarTypes microservice returns the values carA and carB.

Default ConfigSources playground

Now that you've learned the various ways of defining configuration properties, you can see how they all work together.

To review, here are the six places to inject properties:

  • Java annotations @Inject @ConfigProperty with defaultValue in InventoryConfig.java (no ordinal)
  • Properties file through /META-INF/microprofile-config.properties (default ordinal = 100)
  • Environment variables through server.env (default ordinal = 300)
  • System properties through bootstrap.properties (default ordinal = 400)
  • As a variable element in the server.xml file (ordinal = 500)
  • As a appProperties property element in the server.xml file (ordinal = 600)

You can add new properties and override the default ordinal value of the ConfigSource files.

Use the editor to inject new properties into the files. Use @Inject @ConfigProperty (name="propertyName"); to include the new properties in the InventoryConfig.java file. Use propertyName=propertyValue to add the new properties to any of the properties files or the server.env file. Use XML syntax to add the new properties to the server.xml file.

Add the config_ordinal property to override the default ordinal value in any of the ConfigSources.

Click Run to see the file ordinal priority and the property values being used.

Nice work! Where to next?

Nice work! You learned how to use MicroProfile Config to separate configuration from code by using injection and how to provide configuration values with properties files, environment variables, system properties, and the Liberty server.xml file. You also learned the default ordinals for each of these configuration sources and how to override them.

What did you think of this guide?

Extreme Dislike Dislike Like Extreme Like

What could make this guide better?

Raise an issue to share feedback

Create a pull request to contribute to this guide

Need help?

Ask a question on Stack Overflow

Like Open Liberty? Star our repo on GitHub.

Star