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
Propertyenum, as many as you want:SERVER("MY_SERVER", "my.server", "localhost", "The server"), PORT("", "my.port", "1234", "The port");
Basically this says the
Property.SERVERproperty will be filled using:- First, the value of the
MY_SERVERenvironment variable, if it exists, - second, the
my.serverproperty (passed with the-Dflag), if it exists, - and finally, the default value
localhostif 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
@Propannotation: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.