Managing application configuration can often become a complex task, especially as projects grow in scale.
Developers frequently juggle multiple configuration files, system properties, and environment variables, leading to a scattered and hard-to-maintain setup.
A streamlined approach to configuration not only improves developer productivity but also enhances the stability and reliability of the application.
This is where Avaje Config comes into play. It is a lightweight Java configuration library designed to simplify how applications read and manage their settings.
By providing a unified and layered approach, Avaje Config helps you organize your configuration sources logically, making your application setup cleaner and more intuitive.
This post will explore the core features of Avaje Config and demonstrate how it can improve your development workflow.
Understanding the Configuration Hierarchy
Avaje Config organizes settings in a clear, layered hierarchy. When the system looks for a configuration value, it searches through these layers in a specific order until it finds the property.
This ensures that the most specific and immediate settings always take precedence.
The Loading Order
The default loading order is designed to provide maximum flexibility, allowing overrides at different levels:
- System Properties: These are the highest priority. Any property defined as a Java system property (e.g., -Dmy.property=value) will override all other sources.
- Environment Variables: After system properties, Avaje Config checks for environment variables. This is a common way to configure applications in containerized environments like Docker.
- application.properties: Properties defined in a file named application.properties located in the current working directory.
- application.yml: YAML properties from a file named application.yml in the current working directory.
- Classpath application.properties: Properties loaded from a file within the application’s classpath.
- Classpath application.yml: YAML properties loaded from a file within the application’s classpath. This source has the lowest priority.
This layered approach means you can set default values in your classpath files and easily override them for specific environments using environment variables or system properties.
Getting Started with Avaje Config
Integrating Avaje Config into your Java project is straightforward. The first step is to add the necessary dependency to your build configuration.
Maven Dependency
For Maven projects, add the following snippet to your pom.xml file. This includes the core library and the necessary YAML parsing support.
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
<scope>runtime</scope>
</dependency>
Accessing Configuration Properties
Once the dependency is in place, you can start accessing configuration properties using the Config class. It provides a simple, fluent API for retrieving values.
- Get a required property: Config.get(“my.property”)
- Get a property with a default value: Config.get(“my.property”, “defaultValue”)
- Get an integer property: Config.getInt(“my.port”, 8080)
- Get a boolean property: Config.getBool(“feature.toggle”, false)
Leveraging Environment Variables
Modern application development, especially in cloud-native and containerized environments, relies heavily on environment variables for configuration.
Avaje Config provides excellent support for this practice, making it easy to externalize your settings.
Mapping Convention
Avaje Config automatically maps environment variables to the standard dot-notation property names used in Java. The convention is straightforward:
- It converts the variable name to lowercase.
- It replaces underscores (_) with dots (.).
For example, an environment variable named DB_CONNECTION_URL will be mapped to the property key db.connection.url.
This seamless mapping allows you to use the same Config.get(“db.connection.url”) call regardless of whether the value is defined in a .properties file or as an environment variable.
Customizing the Configuration Load Path
While the default loading behavior covers most use cases, you may occasionally need to load properties from a specific file or location. Avaje Config allows you to customize the loading path to fit your project’s needs.
Loading Specific Files
You can direct Avaje Config to load a particular file by setting the load.properties system property.
java -Dload.properties=file:/etc/myapp/override.properties -jar my-app.jar
This command instructs the application to load override.properties first, giving its values the highest precedence after system properties and environment variables.
This is useful for providing environment-specific configurations without modifying the application package.
Implementing Dynamic Property Changes
In some scenarios, configuration values need to change while the application is running without requiring a restart.
Avaje Config supports this through its onChange methods, which allow you to register listeners that react to property changes.
Registering a Listener
You can register a callback to monitor changes to a specific property. This is particularly useful for feature toggles or tuning parameters.
- Listen for changes to a string property:
Config.onChange(“some.setting”, newValue -> {
System.out.println(“some.setting changed to: ” + newValue);
}); - Listen for changes to an integer property:
Config.onChangeInt(“some.number”, newIntValue -> {
System.out.println(“some.number changed to: ” + newIntValue);
}); - Listen for changes to a boolean property (feature flags):
Config.onChangeBool(“feature.x.enabled”, enabled -> {
if (enabled) {
// activate feature X
} else {
// deactivate feature X
}
});
This functionality provides a powerful mechanism for building dynamic, responsive systems.
Next Steps in Your Configuration Journey
Avaje Config provides a robust and flexible solution for managing Java configuration.
Its layered loading mechanism, seamless support for environment variables, and dynamic property features make it a valuable tool for any modern Java application.
By centralizing your configuration logic, you can build applications that are easier to maintain, deploy, and scale.
If you are looking for a way to tame the complexity of your application’s settings, consider giving Avaje Config a try.
Its intuitive design and powerful features can help you streamline your development process and build more resilient systems. Explore the official documentation to learn more about its advanced capabilities.
