Eclipse MicroProfile Config – what is it?

Why do I bother with Configuration?

Separating configuration from code is not a new concept and neither is the need for applications to be configured differently when running on different environments. In recent years the desire to package immutable applications in containers, into which external configuration can be injected, has become a best practice for microservices. There are many strategies to achieve this so that applications do not need to be repackaged when their underlying running environment changes. Microservices are designed to be moved around and run in multiple environments. How do we enable microservices to run in multiple environments without modification? The portable externalization of configuration is key.

What is Eclipse MicroProfile Config?

Eclipse MicroProfile Config is a solution to externalise configuration from microservices. The config properties are provided by ConfigSources. ConfigSources are ordered according to their ordinal, with a higher value taking priority over a lower one. For example, in Websphere Liberty, this means that if the same config is set in server.env (ordinal=300) and in microprofile-config.properties (ordinal=100), then the value from server.env will be used. By default, there are 3 default ConfigSources:

  • System.getProperties() (ordinal=400)
  • System.getenv() (ordinal=300)
  • all META-INF/microprofile-config.properties files on the ClassPath. (default ordinal=100, separately configurable via a config_ordinal property inside each file)

This diagram demonstrates MicroProfile Config in WebSphere Liberty. The server.env contains configs with the ordinal of 300 while the files jvm.options and bootstrap.properties offer configs with the ordinal of 400. If the same config key exists in microprofile-config.properties or server.env and in jvm.options, the config value in jvm.options will be used.

The default values can be specified in the file microprofile-config.properties within the application and the value can be overwritten later for each deployment. A higher ordinal number takes precedence over a lower number.

It is also possible to write and register custom ConfigSources, for example if you want application in your environments to retrieve their config from a central key/value store.

There are a number of Config projects which directly influenced MicroProfile Config and acted as basis for this API, such as:

This project started in October 2016 with 14 amazing contributors. The Config 1.0 API was released in August 2017, followed by Config 1.1 release in September 2017.

Microprofile Config does not contain a “reference implementation” itself but does provide the API specification, a TCK, and documentation.

The following Implementations are available with more on their way:

How to use MicroProfile Config?

MicroProfile Config offers two ways to obtain config properties: programmatically or via CDI injection.

1. Obtain Config programmatically

Below is a code snippet to demonstrate how to get hold of a property named “userId”. First obtain the Config object, which contains all properties this class can access. Then look up the individual property via getValue(String propertyName, Class<?> propertyValueType)

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
 
public class ProgrammticConfigDemo {
    
    public void purchase() {
            Config config = ConfigProvider.getConfig();
            String userId =  config.getValue("userId", String.class);
            purchaseService(userId);
    }
 
    private void purchaseService(String userId) {
            // do something  
    }
}

2. Obtain Config via Injection

Individual property injection - static value

Each individual property can be injected directly, shown below. The injected value is static and the value is fixed on application starting.

import javax.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
 
public class ProgrammticConfigDemo {
    @Inject @ConfigProperty(name="userId") 
      String userId;

    public void purchase() {            
                purchaseService(userId);
    }
 
    private void purchaseService(String userId) {
                // do something     
    }
}

Individual Property Injection - Dynamic

If a property is dynamic, injecting Provider<> will force the value to be retrieved just in time.

import javax.inject.Inject;
import javax.inject.Provider;

import org.eclipse.microprofile.config.inject.ConfigProperty;
 
public class ProgrammticConfigDemo {
    @Inject @ConfigProperty(name="userId")
      Provider<String> userId;

    public void purchase() {             
                purchaseService(userId.get());
    }
 
    private void purchaseService(String userId) {
                // do something  
    }
}

Individual Optional Property Injection

If a property is optional, supply a default value on ConfigProperty.

import javax.inject.Inject;

import org.eclipse.microprofile.config.inject.ConfigProperty;
 
public class ProgrammticConfigDemo {
    @Inject @ConfigProperty(name="userId", defaultValue="me")
    String userId;

    public void purchase() {             
                purchaseService(userId);
    }
 
    private void purchaseService(String userId) {
                // do something  
    }
}

Config Object Injection

The config object can also be injected. Then use the getValue() method to retrieve the individual property.

import javax.inject.Inject;
import org.eclipse.microprofile.config.Config;
 
public class ProgrammticConfigDemo {
    @Inject Config config;

    public void purchase() {            
            String userId =  config.getValue("userId", String.class);
            purchaseService(userId);
    }
 
    private void purchaseService(String userId) {
            // do something     
    }
}

The above example illustrates how to retrieve a mandatory property. If this property does not exist in one or more ConfigSources, a deployment exception will occur.

For an optional property, replace the call to getValue() with a call to getOptionalValue() and replace @ConfigProperty(name=”userId”) with @ConfigProperty(name=”userId”, defaultValue=”me”).

Where to go next?

The API and TCK jars can be found from maven central. The specification can be accessed from here.

We have released MicroProfile Config 1.0 and Config 1.1.

Below is the quick summary of Config 1.1 release content:

  • One default method returning the property names getPropertyNames() was added to ConfigSource
  • The default converters extended to include URL, all primitive types (int, long etc) in addition to the specified primitive type wrappers
  • The default property name for @ConfigProperty has been changed to fully qualified classname (no longer lowercase the first letter of the class, as specified in Config 1.0) followed by the . and variable name.

We are working through the issues on MicroProfile Config repo. The next big item will be to improve the dynamic aspect of Config. If you would like to see new features in the next release, please log some issues there. We have a weekly hangout to discuss the design issues. Please import the MicroProfile Calendar, which can be found from MicroProfile wiki and join the hangout.

Due to the success of this project, the Configuration JSR was proposed with me and Mark Struberg as Spec Lead. Stay tuned on the progress.

About the Author

Emily Jiang

Emily Jiang
IBM