TL;DR: Injection is the process to automatically initialise variables (or parameters) when building an instance.
I'we tried to wrap my head around dagger for a few days until I realised I was missing actually the concept of injections in java (to my defense, I stopped using recent java releases when I entered the corporate world with its crazy inertia -- ColdFusion anyone?). I've found an attempt to describe injection in a simple way which does a very good job, but was still too complex for my poor brain.
ELI5
You have a lunch box where you can get a fruit, a sandwich and a cookie. Mommy and daddy have lots of fruits and cookies and can prepare any sandwich you want. You make a list every day with what you want. The list can be different or not, but can only have one of each tree.
In the morning mommy gives you the box. When you're in your lunch break you open it, you find the fruit, the cookie and the sandwich you wanted in your list.
Injection is making sure that what's in the list will be in the box.
For developers
Your application usually has classes that use other classes (or interfaces). The simple example is of a field in a class:
// All credit goes to Lars Vogel for this code
// (http://www.vogella.com/tutorials/DependencyInjection/article.html)
import java.util.logging.Logger;
public class MyClass {
Logger logger;
public MyClass(Logger logger) {
this.logger = logger;
// write an info log message
logger.info("This is a log message.")
}
}
Traditional
Your class needs to initialise the field somehow and use it (e.g. via calling its methods). In "traditional" programming, one does this via initialising a Logger object and passing it to an instance of MyClass:
//...
public static void main(String [] args) {
Logger logger = Logger.getLogger(MyClass.class.getName());
MyClass(logger);
}
This code is hard-coded; if you change the logger class, you'll need to change the code above too. This may or may not be that easy (e.g. if MyClass has multiple parameters or you have a lot of objects to initialise in cascade).
Configuration
If you look at the above code, one could argue that MyClass depends on Logger and consequently, building a valid instance of MyClass is a configuration problem, not a development one. I think this is the reason behind at least dependency injection. Therefore, we should have some sort of a configuration file telling MyClass
to use Logger.getLogger(MyClass.class.getName())
every time a new instance is created. This way, if we decide to use a class BoboLogger (with the same API as Logger), we'd only need to change the configuration file, not the source code.
This is the approach of @Inject
annotation; a configuration graph is built and objects are initialised based on it. J2EE does it e.g. via XML configuration files when beans are initialised. Dagger for example, does it programatically:
public static void main(String[] args) {
ObjectGraph objectGraph = ObjectGraph.create(...);
MyClass myClass = objectGraph.get(MyClass.class);
// ...
}
You can see in the code that the dependency graph is created and a new MyClass is instantiated.
Use Cases
The main use case for dependency injection is from what I've read testing, more exactly the capability to replace at runtime instantiated objects with e.g. mock objects.
Another use case is to reduce the amount of coding. with the two lines in the Dagger example above, MyClass gets initialised, regardless of how many dependencies it has.
Member discussion: