Injecting environment variables and properties with Guice
Using environment variables is a must for any meaningful project. Using Guice, we can actually directly inject the values of the
variables into our classes, without any clumsy Configuration
class and alike.
This project does just that.
-
Add your variables into the
Property
enum, as many as you want:SERVER("MY_SERVER", "my.server", "localhost", "The server"), PORT("", "my.port", "1234", "The port");
Basically this says the
Property.SERVER
property will be filled using:- First, the value of the
MY_SERVER
environment variable, if it exists, - second, the
my.server
property (passed with the-D
flag), if it exists, - and finally, the default value
localhost
if none of the above is available.
Feel free to customize this logic in
Property.getValue()
. - First, the value of the
-
Directly inject each variable into your class using the
@Prop
annotation:import com.google.inject.Inject import phvu.prop.{Prop, Property} class PropertyUser @Inject() (@Prop(Property.SERVER) val server: String, @Prop(Property.PORT) val port: Int) { def run() = { println(s"I am on $server:$port") } }
This is written in Scala, but using it in Java is very similar.
-
Use Guice to create the injector:
Guice.createInjector(new PropertyModule).getInstance(classOf[PropertyUser]).run()
Don't worry about binding. Those are handled for you.
$ sbt clean compile package assembly
$ MY_SERVER="fooooooooo" java -Dmy.server="mystupidserver" -Dmy.port=342456456 -jar target/scala-2.11/guice-properties-assembly-1.0.jar
I am on fooooooooo:342456456
-
How to use this in my project?
It is up to you. You can copy the classes and freely modify it. However, I would recommend to make this into a separated module, as it will be easier if you need to shade some dependencies (notably Guice and Guava).
-
What if I have some other classes to be injected with Guice?
Be aware that you can create an Injector from multiple Module:
val injector = Guice.createInjector(new PropertyModule, new YourModule...)
Inspired by this, I wanted to re-make the whole project in Scala, but there are some limitation in the way Scala handle annotations, so I had to resorted back to Java.
I also used bindConstant()
instead of bind()
to have Guice automatically do type-casting.