In the era of Micro-services it is essential to be able to externalize and inject both static and dynamic configuration properties for your services. As a matter of fact, microservices are designed to be moved across different environments, therefore it is essential to have a portable externalization of their configuration.

Since WildFly 14 this can be done with the addition of SmallRye implementation of Eclipse MicroProfile Config.

The MicroProfile Config SmallRye subsystem

The MicroProfile config has been implemented in WildFly 14 with the following subsystem:

<subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0"/>

This subsystem in turns requires the following extension:

<extension module="org.wildfly.extension.microprofile.config-smallrye"/>

When this subsystem is activated, the configuration will be injected into the org.eclipse.microprofile.config.Config object. This configuration object contains the information collected from several configuration locations, called ConfigSources and stored in org.eclipse.microprofile.config.spi.ConfigSource. By default there are 3 default ConfigSources:

  1. System.getProperties()
  2. System.getenv()
  3. All META-INF/microprofile-config.properties files on the ClassPath
  4. All entries in microprofile-config-smallrye subsystem

If the same property is defined in multiple ConfigSources, the policy is that the one with highest ordinal number overwrite the lower (So for example if you start the application server with a System Property named "foo", it will override another property named foo in the microprofile-config.properties.

Now let's see all supported ConfigSources locations:

ConfigSources in microprofile-config-smallrye subsystem

You can store properties in the ConfigSource by adding them in the microprofile-config-smallrye subsystem. Let's see an example:

/subsystem=microprofile-config-smallrye/config-source=props:add(properties={"property1" = "value1", "property2" = "value2"})

In terms of XML configuration, this is the outcome:

<subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0">
    <config-source name="props">
        <property name="property1" value="value1"/>
        <property name="property2" value="value2"/>
    </config-source>
</subsystem>

You can reference also properties as files from a directory. For example, if the folder /var/config contains the files:

  • text1
  • text2

We can create a config-source using as target the folder /var/config:

/subsystem=microprofile-config-smallrye/config-source=file-props:add(dir={path=/var/config})

Now our ConfigSource will contain two entries: text1 and text2 and the value is the content of those files.

This results in the XML configuration:

<subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0">
    <config-source name="file-props">
        <dir path="/var/config"/>
    </config-source>
</subsystem>

With that configuration, any application deployed in WildFly can use the above ConfigSource as property. Here is a Servlet example which reads the property1 and property2:

package com.mastertheboss.mp;

import java.io.IOException;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.microprofile.config.inject.ConfigProperty;

@WebServlet(name = "config", urlPatterns = { "/config" })

public class ConfigServlet extends HttpServlet {

    @Inject
    @ConfigProperty(name = "property1")
    String prop1;

    @Inject
    @ConfigProperty(name = "property2")
    String prop2;

    public ConfigServlet() {
        // TODO Auto-generated constructor stub
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Got property1 with: ").append(prop1);
        response.getWriter().append("Got property2 with: ").append(prop2);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}
Please note that applications that are deployed in WildFly must have CDI enabled (e.g. with a "META-INF/beans.xml") or by having CDI Bean annotation) to be able to use MicroProfile Config in their code.

If you don't want to reference the single ConfigProperty, you can also inject the generic org.eclipse.microprofile.config.Config object:

@Inject Config config;

This allows to retrieve the single Property with the get method:

String p =  config.getValue("property1", String.class);

You can also use the getPropertyNames() method to iterate over the list of Properties:

Iterable<String> i = config.getPropertyNames();

In order to compile your project, you'd need to include, besides the EE dependencies, also the Eclipse Microprofile dependency. The latest stable version is the version 1.3:

<dependency>
	<groupId>org.eclipse.microprofile.config</groupId>
	<artifactId>microprofile-config-api</artifactId>
	<version>1.3</version>
</dependency>

One advantage of using the MicroProfile strategy is that property Injection will be checked at deployment time:

Caused by: org.jboss.weld.exceptions.DeploymentException: Error while validating Configuration:
No Config Value exists for prop1

ConfigSource from Class

You can also provide a ConfigSource class which implements org.eclipse.microprofile.config.spi.ConfigSource and acts as source for the ConfigSource. For example, you can provide an implementation of org.eclipse.microprofile.config.spi.ConfigSource that is named com.mastertheboss.MyConfigSource :

package com.mastertheboss.mp;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.eclipse.microprofile.config.spi.ConfigSource;

public class MyConfigSource implements ConfigSource {

    String fileLocation = System.getProperty("user.dir") + "resources/config.properties";

    @Override
    public int getOrdinal() {
        return 400;
    }

    @Override
    public Set<String> getPropertyNames() {
        return getProperties().keySet();
    }

    @Override
    public String getValue(String key) {
        return getProperties().get(key);
    }

    @Override
    public String getName() {
        return "Custom Config Source: file:" + this.fileLocation;
    }

    @Override
    public Map<String, String> getProperties() {
        Map<String, String> map = new HashMap<String, String>();

        Properties properties = new Properties();
        InputStream in;
        try {
            in = new FileInputStream(this.fileLocation);
            properties.load(in);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        for (final String name : properties.stringPropertyNames())
            map.put(name, properties.getProperty(name));

        return map;

    }

}

The class needs to be registered as module and installed. For example, if the class is packaged in a library and installed as "org.mp" module:

/subsystem=microprofile-config-smallrye/config-source=my-config-source:add(class={name=com.mastertheboss.MyConfigSource, module=org.mp})

This results in the XML configuration:

<subsystem xmlns="urn:wildfly:microprofile-config-smallrye:1.0">
    <config-source name="my-config-source">
        <class name="com.mastertheboss" module="org.mp"/>
    </config-source>
</subsystem>

ConfigSources in microprofile-config-smallrye subsystem

Finally, the application is able to extract the ConfigSource by including them into the META-INF/microprofile-config.properties:

eclipse microprofile wildfly

ConfigSources from the property file have priority (in case of clash between properties) over the ConfigSources from the subsystem. However they are overridden by System Properties and Env Properties.

The source code for this example is available at: https://github.com/fmarchioni/mastertheboss/tree/master/micro-services/mp-config-example

WildFly Administration Guide

This article is an excerpt from "WildFly Administration Guide", the only book which is always updated with the newest features of the application server!
0
0
0
s2smodern