»cfg4j« 4.4.x documentation
Table of Contents
This content is open source. Help improve it.
Installation
You can start using cfg4j in your app by simply including it as a dependency. It consists of cfg4j-core module (required) and a number of plugins (e.g. cfg4j-consul, cfg4j-git) which add support for additional configuration sources. Below is the configuration for Gradle and Maven that will get you started quickly. Once you add cfg4j dependency proceed to the usage section.
- Gradle
dependencies {
compile group: "org.cfg4j", name:"cfg4j-core", version: "4.4.0"
// Optional plug-ins
// Consul integration
compile group: "org.cfg4j", name:"cfg4j-consul", version: "4.4.0"
// Git integration
compile group: "org.cfg4j", name:"cfg4j-git", version: "4.4.0"
}
- Maven
<dependencies>
<dependency>
<groupId>org.cfg4j</groupId>
<artifactId>cfg4j-core</artifactId>
<version>4.4.0</version>
</dependency>
<!-- Optional plug-ins -->
<!-- Consul integration -->
<dependency>
<groupId>org.cfg4j</groupId>
<artifactId>cfg4j-consul</artifactId>
<version>4.4.0</version>
</dependency>
<!-- Git integration -->
<dependency>
<groupId>org.cfg4j</groupId>
<artifactId>cfg4j-git</artifactId>
<version>4.4.0</version>
</dependency>
</dependencies>
Quick start
You may want to read the following (a bit lengthy) article about configuration management using cfg4j to get better understanding of the core configuration management concepts.
Add cfg4j-core and cfg4j-git dependencies to your project (see previous paragraph for detail).
Use the following code in your application to connect to the sample configuration source (git repository). Also see this sample app.
public class Cfg4jPoweredApplication {
// "Reksio" is a friendly dog that has many friends
public interface ReksioConfig {
List<String> friends();
}
public static void main(String... args) {
// Select our sample git repository as the configuration source
ConfigurationSource source = new GitConfigurationSourceBuilder()
.withRepositoryURI("https://github.com/cfg4j/cfg4j-git-sample-config.git")
.build();
// Create configuration provider backed by the source
ConfigurationProvider provider = new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withReloadStrategy(new PeriodicalReloadStrategy(5, TimeUnit.SECONDS))
.build();
// Get info about our dog. When you add more friends in the configuration file, object below will automatically reflect that change (by mutating friends() list).
ReksioConfig reksioConfig = configurationProvider.bind("reksio", ReksioConfig.class);
// Display friends of Reksio!
System.out.println(reksioConfig.friends());
}
}
- Optional steps
- Fork the sample configuration repository.
- Add your configuration to the “application.properties” file and commit the changes.
- Update the code above to point to your fork.
Tutorial
Introduction
Using cfg4j is quite simple. It boils down to the following steps:
- Point to the
ConfigurationSource
that stores your configs (e.g. Consul K-V store, git repository, local files, classpath resources). - Create
ConfigurationProvider
backed by your configuration source. - Access your configuration in one of the two ways:
- Directly through ConfigurationProvider methods (e.g.
getProperty("my.property", Integer.class)
) - Through a binding mechanism. Simply create an interface with methods representing your configuration variables and ask ConfigurationProvider to create a configuration object implementing your interface (i.e. calling
bind("my.configuration.set", MyInterface.class)
). Every time the configuration changes your object will be automatically updated with new values.
- Directly through ConfigurationProvider methods (e.g.
- (optional) If you want you can customize the ConfigurationProvider behavior by using:
ReloadStrategy
- those allow configuration to be automatically reloaded. There’sPeriodicalReloadStrategy
provided that can reload configuration after every specified time period. You can also implement your own strategy.Environment
- Use it to specify where your configuration is located inside ConfigurationSource. It’s especially useful when you have multiple configuration sets (e.g. multi-tenant) in one source (e.g. under different paths, on different git branches, etc.). Read more below.
Configuration source
Obviously, you need your configuration to be stored somewhere before you can access it. You can store it in a K-V store (e.g. Consul K-V), files (remote git repository, local files, classpath resources) or a relational database. If you’re unsure what the best practices are, you can consult this article.
Once you have your configuration in place, create a ```ConfigurationSource`` object that will fetch it. Here’s an example using Consul K-V.ConfigurationSource source = new ConsulConfigurationSourceBuilder().build();
To learn more about supported configuration sources and their capabilities head to the PLUGINS section.
Configuration provider
Once we have ConfigurationSource
in place, we need ConfigurationProvider
that will provide your app with a uniform interface for reading configs.
You can obtain ConfigurationProvider
using builder:ConfigurationSource source = ... (see above)
ConfigurationProvider provider = new ConfigurationProviderBuilder().withConfigurationSource(source).build();
You can also use DI container (like Spring)@Bean
public ConfigurationProvider configurationProvider(ConfigurationSource source) {
return new ConfigurationProviderBuilder().withConfigurationSource(source).build();
}
Accessing configuration
Once you have ConfigurationProvider
in hand you can use it for accessing configuration. Here’s a bunch of examples (values that you need to put in your configuration source are listed in comments next to examples).
- Get primitive (and boxed) types directly from Provider (also see this sample app).
Boolean property = provider.getProperty("some.property", Boolean.class); // some.property=false
Integer property = provider.getProperty("some.other.property", Integer.class); // some.other.property=1234
float[] floats = provider.getProperty("my.floatsArray", float[].class); // my.floatsArray=1.2,99.999,0.15
URL url = provider.getProperty("my.url", URL.class); // my.url=http://www.cfg4j.org
- Get collections directly from Provider
List<String> stringList = provider.getProperty("some.string.list", new GenericType<List<String>>() {}); // some.string.list=how,are,you
Map<String, Integer> pairs = provider.getProperty("some.map", new GenericType<Map<String, Integer>>() {}); // some.map=a=1,b=33,c=-10
- Utilize object binding (also see this sample app).
// Define your configuration interface
public interface MyConfiguration {
Boolean featureToggle();
File[] someFiles();
Map<String, Integer> prices();
}
// someFeature.featureToggle=true
// someFeature.someFiles=/temp/fileA.txt,/temp/fileB.txt
// someFeature.prices=apple=1,candy=33,car=10
MyConfiguration config = simpleConfigurationProvider.bind("someFeature", MyConfiguration.class);
// Use it (when configuration changes your object will be auto-updated!)
if(config.featureToggle()) {
...
}
Configuration reloading
Being able to change your configuration without bringing the service down is extremely important for web apps. CFG4J provides runtime configuration reloading which can be configured using ReloadStrategy
. When configuration gets reloaded all bound configuration objects (see “Accessing configuration” above) will be updated.
- Reload configuration periodically (also see this sample app).
// Reload every second
ConfigurationProvider provider = new ConfigurationProviderBuilder()
.withConfigurationSource(...)
.withReloadStrategy(new PeriodicalReloadStrategy(1, TimeUnit.SECONDS))
.build();
- Reload on-demand (e.g. triggered by push mechanism)
// Implement your strategy
public class MyReloadStrategy implements ReloadStrategy {
public void register(Reloadable resource) {
...
resource.reload();
...
}
}
ConfigurationProvider provider = new ConfigurationProviderBuilder()
.withReloadStrategy(new MyReloadStrategy())
.build();
Multi-tenant support (a.k.a. environment selection)
You may want to store multiple configuration sets in a single configuration store (e.g. to support different environments [dev, test, prod] in your app or simplify because you want to maintain one store for multiple tenants).
To support this use case cfg4j introduces Environments. Environment
is simply a way to tell the provider where in the store is your configuration set located. Because each source may support environments differently (e.g. in git you could use separate branches or directories, in K-V store you could use different paths, etc.).
For now we’re keeping it simple. Environment
has a name that is interpreted by the source. It’s up to the source what interpretation to use. Consult documentation for each of the sources (plugins) for more detail.
You can provide Environment
to the provider in the following way:ConfigurationProvider provider = new ConfigurationProviderBuilder()
.withConfigurationSource(new ConsulConfigurationSourceBuilder().build())
.withEnvironment(new ImmutableEnvironment("myApplication/prod")) // each conf variable will be prefixed with this value when fetching from Consul
.build();
Different file types support (YAML, properties)
When reading from ConfigurationSource
that is backed by files (e.g. git repository) you have an option of using either plain properties files or YAML files. Cfg4j will automatically recognize the file by its extension (.properties or .yaml).
Merging configurations from multiple sources
You can merge configs from multiple configuration sources. To do that use MergeConfigurationSource
as seen below:ConfigurationSource source1 = ...
ConfigurationSource source2 = ...
ConfigurationSource mergedSource = new MergeConfigurationSource(source1, source2);
Fallback in case of failure
When working in a distributed environment failure happen all the time. You may consider using multiple sources. When one fails another one will be used as a fallback. You can use FallbackConfigurationSource
in the following way:ConfigurationSource source1 = ...
ConfigurationSource source2 = ...
ConfigurationSource mergedSource = new FallbackConfigurationSource(source1, source2);
Metrics
Most of the cfg4j components are instrumented. Metrics are exposed with support from Dropwizard’s Metrics library. You can see the number of invocations (e.g. how many times your configuration was reloaded) and execution time (e.g. how long does it take to fetch configuration from external configuration source - git repository or Consul). To enable instrumentation you have to provide ConfigurationProvider
with Metric’s MetricRegistry
. To easily differentiate between metrics for different provided you can specify prefix prepended to all metric names constructed for the given provider.@Autowired
private MetricRegistry metricRegistry;
@Bean
public ConfigurationProvider configurationProvider() {
...
return new ConfigurationProviderBuilder()
...
.withMetrics(metricRegistry, "firstProvider.") // Enable metrics with prefix
.build();
}
Extensions
Classpath
- Read configuration from multiple files located in classpath. Also see this sample app.
// Specify which files to load. Configuration from both files will be merged.
ConfigFilesProvider configFilesProvider = () -> Arrays.asList(Paths.get("application.properties"), Paths.get("otherConfig.properties"));
// Use classpath as configuration store
ConfigurationSource source = new ClasspathConfigurationSource(configFilesProvider);
// Create provider
return new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.build();
Files
- Read configuration from multiple files located in a given path. Also see this sample app.
// Specify which files to load. Configuration from both files will be merged.
ConfigFilesProvider configFilesProvider = () -> Arrays.asList(Paths.get("application.properties"), Paths.get("otherConfig.properties"));
// Use local files as configuration store
ConfigurationSource source = new FilesConfigurationSource(configFilesProvider);
// (optional) Select path to use
Environment environment = new ImmutableEnvironment("/config/root/path/");
// (optional) Reload configuration every 5 seconds
ReloadStrategy reloadStrategy = new PeriodicalReloadStrategy(5, TimeUnit.SECONDS);
// Create provider
return new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withEnvironment(environment)
.withReloadStrategy(reloadStrategy)
.build();
Git
- Use remote or local git repository that reloads configuration every 5 seconds. Also see this sample app.
// Use Git repository as configuration store
ConfigurationSource source = new GitConfigurationSourceBuilder()
.withRepositoryURI("https://your/git/repo.git")
.build();
// (optional) Reload configuration every 5 seconds
ReloadStrategy reloadStrategy = new PeriodicalReloadStrategy(5, TimeUnit.SECONDS);
return new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withReloadStrategy(new PeriodicalReloadStrategy(5, TimeUnit.SECONDS))
.build();
- Read configuration from a given files (defaults to application.properties). Also see this sample app.
ConfigFilesProvider configFilesProvider = () -> Arrays.asList(Paths.get("application.properties"), Paths.get("otherConfig.properties"));
// Use Git repository as configuration store
ConfigurationSource source = new GitConfigurationSourceBuilder()
.withRepositoryURI("https://your/git/repo.git")
.withConfigFilesProvider(configFilesProvider)
.build();
// (optional) Reload configuration every 5 seconds
ReloadStrategy reloadStrategy = new PeriodicalReloadStrategy(5, TimeUnit.SECONDS);
return new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withEnvironment(environment)
.build();
Multi-tenant support (multiple configuration sets per source)
- Read configuration from a given branch (defaults to master). Also see this sample app.
// Use Git repository as configuration store
ConfigurationSource source = new GitConfigurationSourceBuilder()
.withRepositoryURI("https://your/git/repo.git")
.build();
// Select branch to use (use new DefaultEnvironment()) for master
Environment environment = new ImmutableEnvironment("myBranch");
// (optional) Reload configuration every 5 seconds
ReloadStrategy reloadStrategy = new PeriodicalReloadStrategy(5, TimeUnit.SECONDS);
return new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withEnvironment(environment)
.build();
- Read configuration from files (see examples above to change list of files) at a given path.
// Use Git repository as configuration store
ConfigurationSource source = new GitConfigurationSourceBuilder()
.withRepositoryURI("https://your/git/repo.git")
.build();
// Select branch and path
Environment environment = new ImmutableEnvironment("myBranch/folder/on/branch");
// (optional) Reload configuration every 5 seconds
ReloadStrategy reloadStrategy = new PeriodicalReloadStrategy(5, TimeUnit.SECONDS);
return new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withEnvironment(environment)
.build();
Consul
- Connect to local Consul agent and reload configuration every 5 seconds. Also see this sample app.
// Use Consul service as configuration store
ConfigurationSource source = new ConsulConfigurationSourceBuilder().build();
// (optional) Reload configuration every 5 seconds
ReloadStrategy reloadStrategy = new PeriodicalReloadStrategy(5, TimeUnit.SECONDS);
// Create provider
return new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withReloadStrategy(reloadStrategy)
.build();
- Connect to remote Consul agent and reload configuration every 5 seconds.
// Use Consul service as configuration store
ConfigurationSource source = new URL("http", "192.168.0.1", 8500, "");
// (optional) Reload configuration every 5 seconds
ReloadStrategy reloadStrategy = new PeriodicalReloadStrategy(5, TimeUnit.SECONDS);
// Create provider
return new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withReloadStrategy(reloadStrategy)
.build();
Multi-tenant support (multiple configuration sets per repository)
- Read configuration from a given prefix (defaults to no prefix).
// Use Consul service as configuration store
ConfigurationSource source = new ConsulConfigurationSource();
// Set k-v store directory (i.e. /us-west-2/)
Environment environment = new ImmutableEnvironment("us-west-2");
// (optional) Reload configuration every 5 seconds
ReloadStrategy reloadStrategy = new PeriodicalReloadStrategy(5, TimeUnit.SECONDS);
// Create provider
return new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withEnvironment(environment)
.build();
This content is open source. Help improve it.