A ConfigSource
is exactly what its name says: a source for configured values.
The Config
uses all configured implementations of ConfigSource
to look up the property in question. Dynamically added config sources after the Config
object has been built would be ignored,
which means Config.getConfigSources
always returns the same collection of ConfigSource
s. The same rule applies to ConfigSourceProvider.getConfigSources
.
Each ConfigSource
has a specified ordinal
, which is used to determine the importance of the values taken from the associated ConfigSource
.
A higher ordinal
means that the values taken from this ConfigSource
will override values from lower priority ConfigSources.
This allows a configuration to be customized from outside a binary, assuming that external ConfigSource
s have higher ordinal
values than the ones whose values originate within the release binaries.
It can also be used to implement a drop-in configuration approach.
Simply create a jar containing a ConfigSource
with a higher ordinal and override configuration values in it. Specifying an empty string as the value effectively erases the property.
If the jar is present on the classpath then it will override configuration values from ConfigSources with lower ordinal
values.
Note that a special property config_ordinal
can be set within any built-in ConfigSource
implementation.
The default implementation of getOrdinal()
will attempt to read this value.
If found and a valid integer, the value will be used.
Otherwise the respective default value will be used.
config_ordinal = 120
com.acme.myproject.someserver.url = http://more_important.server/some/endpoint
A MicroProfile Config implementation must provide ConfigSources for the following data out of the box:
-
System properties (default ordinal=400).
-
Environment variables (default ordinal=300).
-
A
ConfigSource
for each property fileMETA-INF/microprofile-config.properties
found on the classpath. (default ordinal = 100).
Some operating systems allow only alphabetic characters or an underscore, _
, in environment variables. Other characters such as ., /
, etc may be disallowed. In order to set a value for a config property that has a name containing such disallowed characters from an environment variable, the following rules are used.
The ConfigSource
for the environment variables searches three environment variables for a given property name (e.g. com.ACME.size
):
-
Exact match (i.e.
com.ACME.size
) -
Replace each character that is neither alphanumeric nor
_
with_
(i.e.com_ACME_size
) -
Replace each character that is neither alphanumeric nor
_
with_
; then convert the name to upper case (i.e.COM_ACME_SIZE
)
The first environment variable that is found is returned by this ConfigSource
.
ConfigSources are discovered using the java.util.ServiceLoader
mechanism.
To add a custom ConfigSource
, implement the interface org.eclipse.microprofile.config.spi.ConfigSource
.
public class CustomDbConfigSource implements ConfigSource {
@Override
public int getOrdinal() {
return 112;
}
@Override
public Set<String> getPropertyNames() {
return readPropertyNames();
}
@Override
public Map<String, String> getProperties() {
return readPropertiesFromDb();
}
@Override
public String getValue(String key) {
return readPropertyFromDb(key);
}
@Override
public String getName() {
return "customDbConfig";
}
}
Then register your implementation in a resource file /META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource
by including the fully qualified class name of the custom implementation in the file.
If you need dynamic ConfigSources you can also register a ConfigSourceProvider
in a similar manner.
This is useful if you need to dynamically pick up multiple ConfigSources of the same kind;
for example, to pick up all myproject.properties
resources from all the JARs in your classpath.
A custom ConfigSourceProvider
must implement the interface org.eclipse.microprofile.config.spi.ConfigSourceProvider
.
Register your implementation in a resource file /META-INF/services/org.eclipse.microprofile.config.spi.ConfigSourceProvider
by including the fully qualified class name of the custom implementation/s in the file.
An example which registers all YAML files with the name exampleconfig.yaml
:
public class ExampleYamlConfigSourceProvider
implements org.eclipse.microprofile.config.spi.ConfigSourceProvider {
@Override
public List<ConfigSource> getConfigSources(ClassLoader forClassLoader) {
List<ConfigSource> configSources = new ArrayList<>();
Enumeration<URL> yamlFiles
= forClassLoader.getResources("sampleconfig.yaml");
while (yamlFiles.hasMoreElements()) {
configSources.add(new SampleYamlConfigSource(yamlFiles.nextElement()));
}
return configSources;
}
}
Please note that a single ConfigSource
should be either registered directly or via a ConfigSourceProvider
, but never both ways.
As a ConfigSource
is a view of configuration data, its data may be changing, or unchanging.
If the data is changing, and a ConfigSource
can represent its changes, we call that ConfigSource
a dynamic ConfigSource
, since at any two moments two operations on it may reflect two different sets of underlying configuration data.
If instead the data is unchanging, we call the ConfigSource
a static ConfigSource
, since at any two moments two operations on it will reflect only one set of underlying (unchanging) configuration data.
A caller cannot know whether a ConfigSource
is dynamic or static.
For the property lookup, the method config.getValue()
or config.getOptionalValue()
retrieves the up-to-date value.
Alternatively, for the injection style, the following lookup should be used to retrieve the up-to-date value.
@Inject
@ConfigProperty(name="myprj.some.dynamic.timeout", defaultValue="100")
private jakarta.inject.Provider<Long> timeout;
Whether a ConfigSource
supports this dynamic behavior or not depends on how it’s implemented.
For instance, the default ConfigSource
microprofile-config.properties and Environment Variables are not dynamic
while System Properties are dynamic by nature. MicroProfile Config Implementation can decide whether
a ConfigSource
can be dynamic or not.
If a ConfigSource
implements the java.lang.AutoCloseable
interface then the close()
method will be called when the underlying Config
is being released.