Avaje Config
avaje-config provides external configuration for JVM apps. We can provide configuration via yaml or properties files and specify which files to load using command line argument and resources.
License | Source | API Docs | Issues | Releases |
---|---|---|---|---|
Apache2 | Github | Javadoc | Github |
Dependency
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>2.4</version>
</dependency>
Expression evaluation
Expressions start with ${
end with }
. They can optionally
define a default value using a :
as we see in the example below for the
username and password which have default values of mydb
and notSecure respectively.
Expressions are evaluated using environment variables, system properties as well as other properties.
example
app.name: myapp
images.home: ${user.home}/myapp/images
datasource:
db:
username: ${DB_USER:mydb}
password: ${DB_PASS:notSecure}
url: ${DB_URL}
Loading configuration
avaje-config provides ways to load external configuration for running an application and running tests. It also provides a simple mechanism to make it easy to run the application locally (typically in order to run integration tests locally).
Running app
There are four main ways to provide configuration used for the purpose of running the application.
- 1. Default values via
src/main/resources
- 2. Command line arguments
- 3. load.properties
- 4. Plugins
1. Default values via main resources
We can provide "default" configuration values by putting into src/main/resources
either application.yaml
or application.properties
.
These values act as default values and can be overwritten by configuration provided by other sources such as files specified by command line arguments.
2. Command line arguments
We can specify external configuration files to use via command line arguments.
Arguments proceeded by -P
are considered possible configuration files
and avaje-config will try to load them. If they are not valid files that exist
then they are ignored.
example
java -jar myapp.jar -P/etc/config/myapp.properties -P/etc/other.yaml
In the example above 2 external files are configuration files that are loaded providing configuration values for the application.
3. load.properties
Optionally we specify a load.properties
property to define configuration
files to load.
example in application.yaml
## we don't need to specify path if it's in src/main/resources
load.properties: local.properties /etc/other.yaml
After default configuration files are loaded the load.properties property is read and if specified these configuration files are loaded.
4. Plugins
We can also use plugins that implement ConfigurationSource to load configuration from other sources. Refer to the Plugins section for more details.
Running Tests
To provide configuration for running tests add into src/test/resources
either
application-test.yaml
or application-test.properties
.
The configuration from these files is loaded and used when running tests. This configuration
will override any configuration supplied by files in src/main/resources
.
Running locally
When we run our application locally we can provide configuration for this
via properties or yaml files in a ~/.localdev
directory.
For example, when running locally we want to provide configuration that configures our application to use a local database. We want to do this when we run integration tests locally running application(s).
app.name
We must specify a app.name property to do this.
example
app.name=myapp
Then in ~/.localdev
put a yaml or properties configuration file
using the app.name. For example, given app.name=myapp
have
either ~/.localdev/myapp.yaml
or ~/.localdev/myapp.properties
define the configuration we want to use when running locally.
Startup
avaje-config will initialise and load configuration when it is first used.
Initialisation
- Loads all the configuration files
- Performs expression evaluation on all the values
- Using ServiceLoader finds and loads all ConfigurationSource plugins
- Checks
config.load.systemProperties
and loads into system properties if set - Checks
config.watch.enabled
and starts file watching if set
config.load.systemProperties
If we set config.load.systemProperties
to true then all the properties that
have been loaded are then set into system properties.
File watching
If config.watch.enabled
is set to true then avaje-config will
watch the config files and reload configuration when the files change.
By default it will check the config files every 10 seconds. We can change this by setting
config.watch.period
example
config:
watch:
enabled: true
period: 5 ## check every 5 seconds
We can use this as a simple form of feature toggling. For example if we are using kubernetes and have configuration file based on a config map, we can edit the config map to enable/disable features.
config.watch.enabled: true
## some config values to toggle features on/off
feature.cleanup.enabled: true
feature.processEmails.enabled: false
if (Config.enabled("feature.cleanup.enabled") {
...
}
Config
We use Config
to access the application configuration. Config can be used
anywhere in application code - static initialisers, constructors etc. There is no limitation
on where we can use Config.
Config
has convenient static methods to access the underlying configuration and
this is how the majority of applications will use it. It also has
asConfiguration() to return the underlying configuration
and asProperties() to return the loaded configuration as standard
properties.
Get property
Config
provides method to get property values as String, int, long, boolean,
BigDecimal, Enum and URL.
examples
// get a String property
String value = Config.get("myapp.foo");
// with a default value
String value = Config.get("myapp.foo", "withDefaultValue");
int port = Config.getInt("app.port");
long val = Config.getInt("foo", 42);
long port = Config.getLong("app.port");
long val = Config.getLong("foo", 42);
boolean val = Config.getBool("feature.cleanup");
boolean val = Config.getBool("feature.cleanup", true);
// Config.enabled() is an alias for Config.getBool()
boolean val = Config.enabled("feature.cleanup");
boolean val = Config.enabled("feature.cleanup", true);
BigDecimal val = Config.getDecimal("myapp.tax.rate");
BigDecimal val = Config.getDecimal("myapp.tax.rate", "12.5");
MyEnum val = Config.getEnum(MyEnum.class, "myapp.code");
MyEnum val = Config.getEnum(MyEnum.class, "myapp.code", MyEnum.DEFAULT);
URL val = Config.getURL("other.url");
URL val = Config.getURL("other.url", "https://other:8090");
List and Set
We can also return configuration values as List or Set of String, int and long.
List<Integer> codes = Config.getList().ofInt("my.codes", 42, 54);
Set<String> operations = Config.getSet().of("my.operations", "put", "delete");
Set property
Use setProperty()
to set configuration values.
When we set values this will fire any configuration callback listeners that are registered for the key.
Config.setProperty("other.url", "https://bazz");
Config.setProperty("feature.cleanup", "false");
On change
We can register callbacks that execute when a configuration key has it's value changed.
example
Config.onChange("other.url", newUrl -> {
// do something interesting with the changed
// config value
...
});
asProperties()
Obtain all the configuration values as standard properties using Config.asProperties()
Properties properties = Config.asProperties();
asConfiguration()
Obtain the underlying configuration via Config.asConfiguration()
.
Config is providing static singleton scope for the underlying Configuration.
We generally always use Config because it is convenient and there should not
be much need to access the underlying configuration.
Configuration configuration = Config.asConfiguration();
Plugins
Plugins implement the ConfigurationSource
interface and found
and registered via ServiceLoader
. This means they have a
file at src/main/resources/META-INF/services/io.avaje.config.ConfigurationSource
which contains the class name of the implementation.
Plugins implement the method
void load(Configuration configuration);
They are able to use configuration to read properties if needed, for example read the host name of a redis server to read configuration from.
Plugins typically read their configuration source and then use setProperty(key, value)
to set the properties into configuration. The values can contain expressions and will have
their expressions evaluated as part of setProperty.
Refer to the (silly) example plugin - MyExternalLoader.java