In virtually all projects you need to read properties from external sources such as a file. In many cases you also need to be able to override some properties when doing integration testing and sometimes you need to support changing the property values at runtime etc. The Spring framework for Java has some good support for properties but there may be cases where you don’t use Spring and bringing it in just for the sake of property management can be considered an overkill. In this blog we will explore the Owner framework which is a nice framework for managing properties in Java.
Simple Example
In it’s most simple form you create an interface that extends from the org.aeonbits.owner.Config
interface in Owner. For example:
[java]
@Sources(“classpath:my_properties.properties”)
public interface MyConfig extends Config {
@Key(“property1”)
@DefaultValue(“10”)
int property1();
@Key(“property2”)
@DefaultValue(“false”)
boolean property2();
}
[/java]
The Sources
annotation tells Owner to load a property file called my_properties.properties
from the classpath. The property file may look like this:
[bash]
property1=11
property2=true
[/bash]
The DefaultValue
annotation instructs Owner to use a default value of 10 for property1 and false for property2 if they are not defined in the property file. In order to bootstrap Owner you do like this:
[java]
MyConfig myConfig = ConfigFactory.create(MyConfig.class);
[/java]
Overriding Properties
Having your properties loaded from classpath is probably not the best approach for a real application. You probably want to be able to load the property file from the file system somewhere. This is also really simple with Owner:
[java]
@Sources({“file:config/my_file_properties.properties”,
“classpath:my_properties.properties”})
public interface CacheConfig extends Config {
@Key(“property1”)
@DefaultValue(“10”)
int property1();
@Key(“property2”)
@DefaultValue(“false”)
boolean property2();
}
[/java]
All we’ve done here is to instruct Owner to load another property file. The property files are loaded in priority order which means that if a property is found in the my_file_properties.properties
file it’ll have precedence over the property defined in my_properties.properties
.
Using System Properties
But what if we want to override the configurations in an integration test? One way to do this is to make use of a system properties. For example:
[java]
System.setProperty(“property1”, 4);
[/java]
In order for Owner to also use system properties we simply add it as an argument to the factory method:
[java]
MyConfig myConfig = ConfigFactory.create(MyConfig.class, System.getProperties());
[/java]
Using System Environment
Another useful thing is to be able to override properties defined as JVM environment variables. For example if you’re packaging your application as an uber-jar it would be nice to be able to override properties when starting the app:
[bash]
java -jar myapp.jar -Dproperty1=30
[/bash]
To do this you can simple add System.getenv()
to the factory method:
[java]
MyConfig myConfig = ConfigFactory.create(MyConfig.class, System.getenv());
[/java]
You can of course combine both system properties and system environment:
[java]
MyConfig myConfig = ConfigFactory.create(MyConfig.class,
System.getProperties(),
System.getenv());
[/java]
System.getProperties()
will have priority over System.getenv()
in this case.
Hot Reloading
Another nice feature of Owner is that you can easily configure it to reload the property values at runtime. This can be very useful in cases where you want to avoid downtime by just having to change a piece of configuration. Owner supports both synchronous and asynchronous hot reloading of properties. We will look at the asynchronous version here. What you do first is to let your config class also extend the Reloadable
interface:
[java]
public interface MyConfig extends Config, Reloadable {
..
}
[/java]
Next you add the HotReload
annotation:
[java]
@HotReload(value = 30L, unit = TimeUnit.SECONDS, type = ASYNC)
public interface MyConfig extends Config, Reloadable {
@Key(“property1”)
@DefaultValue(“10”)
int property1();
@Key(“property2”)
@DefaultValue(“false”)
boolean property2();
}
[/java]
This instructs Owner to asynchronously reload all properties in this configuration every 30th second. You can read more on property reloading here.
Conclusion
There’s a lot more to Owner then what’s presented here, for example parameterization, type conversions, event support, meta configuration and more. Owner has proven to work really well in my current project and I think it’s easy to use and get started with.
Looks pretty same as Properties https://github.com/yandex-qatools/properties
That library is really great :D