Resolving your problems with Dependency Injection
design
java
scala
programming
No Silver Bullet
wrote Brooks in the far away 1986. The history of software engineering proved him right, there is no doubt. Through the past years, hundreds of theories, patterns, frameworks, technologies risen as fast as they successively fallen. Many design patterns written by the Gang of four have not any application in modern age of computer science. Take as an example, the Singleton pattern.
Focus on design patterns, there is one that from its definition broke down the developer community, the dependency injection. In this post I will introduce the pattern, giving the basis for developing a discussion on pattern pros and cons in the next post of this series.
So, let’s start from the beginning: dependency injection definition.
Definition
The definition of dependency injection was first given by Martin Fowler in the blog post Inversion of Control Containers and the Dependency Injection pattern. The dependency injection is an Enterprise pattern, which aim is to
separate the responsibility of resolving object dependency from its behaviour.
First of all, what is a dependency between two classes? Take a look to the following class diagram:
The class MovieLister
has an attribute, finder
, of type MovieFinder
. So, we used to say that the class
MovieLister
has a dependency from the class MovieFinder
. Between two classes there could be a lot of different types
of dependency, some stronger than others, but here we are going to focus on property dependencies.
Clearly, letting a class to explicitly create an instance of another class tightly coupled the two implementations, increasing the dependency between them.
Defining the dependency between two classes as an function directly proportional to the probability of correlate changes in the classes, we immediately understand that dependency should be minimize.
A first attempt to solve this problem is to use a factory class that creates instances of MovieFinder
. In this way,
MovieLister
minimize the dependency from MovieFinder
, referring only to the defined interface.
But again, we have a problem: now MovieLister
has a dependency with the implementation of MovieFinderFactory
(and,
most important, we decided to implement the factory as a Singleton…WTF!). Moreover, we certainly have more than a
single dependency in a class, which leads to a plethora of factories rising. And dependencies can have dependencies, and
so on.
Clearly, the path is traced, but we have to take a step over to get the optimal solution. Here it comes the idea of Martin Fowler. Why don’t we take the factory idea to the limit and we create a module that is responsible to resolve dependency among classes?
This module is called dependency injector and it is to all effects a container. Applying the Inversion of Control pattern, typical of all modern frameworks, it owns the life cycle of all objects defined under its scope. As a deus ex machina of object’s life, he is able to resolve the dependency Directly Acyclic Graph (DAG) identified among these objects.
Well, this is the right way. The only things we still miss are the following:
- A way to signal to the injector that a class has a certain dependency
- A way to instruct (or configure) the injector to resolve dependencies
Constructor injection versus Setter injection
Since dependencies are nothing more then objects attributes (more or less), the injector has to be instructed to know how to fulfill these attributes. In Java there are three ways to set attributes of an object, which are:
- Using the proper constructor
- Using setters after the object was build using the default constructor
- Using Reflection mechanisms
Once you have selected your preferred way, you will annotate the corresponding statement with the @Inject
annotation.
The annotation and its behaviour are defined inside a JSR. Dependency injection is so important in the Java ecosystem
that there are two dedicated JSRs, i.e. JSR-330 and JSR-299.
Constructor dependency injection
If you want the injector to use the constructor to inject the dependency of a class, annotate the constructor with
@Inject
.
Every time you will ask the injector an instance of a MovieLister
, it will know that it has to use the constructor
annotated with the @Inject
annotation to build the object. So, the dependency are identified as the annotated
constructor parameters.
This is the preferred and correct way to use the dependency injection. Because the object is build using a constructor, this behaviour favors the use of immutable objects and do not break the information hiding principle.
Setter dependency injection
Since the definition of the Java programming language, the aim of the Sun Microsystem was standardization. The Java Bean Specification stated that a java bean must have a default constructor and a couple of getter and setter methods for each attribute it owns. Having defined a standard way of creating objects, the Sun built a plethora of standards and interfaces on it, that are the basis of the JEE specification.
Clearly, outside the JEE specification, this way of creating object is insane. It leads to objects that after creation could be partially filled, does not favor immutability and breaks information hiding.
But, any solution of dependency injection in the Java ecosystem should also treat the "Java bean" way. To
instruct the injector to use setter methods to create an object, annotate the setter methods with the @Inject
annotation.
The injector
There are many implementations in the Java ecosystem of dependency injectors. Each implementation differs from each others essentially for these features:
- How the injector is configure to find the beans it has to manage
- How it resolves the dependencies’ DAG
- How it maintains the instances of managed beans.
The mainstream injectors are the following:
- Google Guice: Guice is a lightweight dependency injection framework that uses
Java configuration, implements both types of injection (constructor and setter injection) and maintains managed
instances with a
Map<Class<?>, Object>
- Spring injector: this component
is the core component of the Spring suite. It is not quite lightweight as Guice,
but it is fully integrated with the whole Spring ecosystem. It implements all type of injection; it provides an XML
style of configuration and a Java style. Differently from Guice, the container is a
Map<String, Object>
, that associates each managed instance with a label. It also support auto discovery of beans through classpath scanning - Weld: Weld is the reference implementation of the CDI specifications given in the JSR-299.
To discover which beans it has to manage, it performs classpath scanning at the startup. You can also configure it
using both Java configuration (factories) and XML configuration (
beans.xml
). Being the reference CDI implementation, it integrates very tightly with JEE, adding to simple DI concepts more sophisticated techniques to manage enterprise beans.
Clearly, the detailed presentation of the above frameworks is behind the scope of this post. However, let me to show an example of dependency resolution using Google Guice.
First of all, we have to configure the injector to find the beans it has to manage. In Guice the configuration is done
directly in Java, extending the framework class AbstractModule
.
The code above configures Guice to resolve every dependency from interface MovieFinder
with its concrete implementation
ColonMovieFinder
. Clearly, bind
is a method of the AbstractModule
class, whereas to
is a method of a class that
implements the builder design pattern (LinkedBindingBuilder
, for sake of completeness).
Using the @Inject
annotation you can annotate every dependency you want to be resolved by Guice. Then, to create an
instance of the injector, you can use a factory method of the Guice
class.
The factory method pass to the injector the classes that store the proper configuration. When you will ask to the
injector an instance of a class that is annotated with an @Inject
annotation and for which it is present a binding
rule, the injector will do the magic for you. In the above example, the following steps are taken by the injector
- The
MovieLister
class definition is loaded within the framework - The class is inspected and it is found that the class declares a dependency from the
MovieFinder
interface - Guice looks at its configuration to find a concrete binding to the
MovieFinder
interface. The binding is found inside theMovieModule
class - Guice resolve the dependency with an instance of the
ColonMovieFinder
class, using the constructor ofMovieLister
to create the new instance of the class
That’s so easy!
The story so far
Clearly, this is only the introduction of the dependency injection story. There are a lot of features that
characterize this pattern. For example, the ability to decide if a class should be or not a singleton, using the
@Singleton
annotation on class definition.
Using dependency injection with Scala
Scala is a language that runs on top of the JVM. The language itself has it own techniques to deal with the dependency
injection. But, if you have to mix Java and Scala code inside the same project, you have to resume the JSR-330. The
@Inject
annotation can be used also in the scala code.
The only thing you have to remember is that the Scala syntax is different from the Java syntax. Scala mixes the
definition of the class with the definition of its main constructor. Then, using the constructor injection means to add
a @Inject
annotation immediately before the list of constructor arguments.
But, why the hell have parenthesis to add a ()
couple of parenthesis after the annotation? The parenthesis are necessary
because, otherwise, how could you tell if (val finder: MovieFinder)
is constructor parameter list or arguments to
@Inject
?
What’s next?
This small post is only an introduction to dependency injection. The internet community is divided on the real usefulness of the pattern. In the next posts of this series I will try to analyze the pros and cons of using this pattern.