Inversion of Control vs Dependency Injection

Background

Lately, I have been interviewing candidates for a Developer role and realised how much confusion there is, still, around the concepts of Inversion of Control and Dependency Injection. The majority of people use both terms interchangeably. Probably, the confusion derives from the heavy use of those concepts on Spring, where Inversion of Control is used to enable Dependency Injection.

This post aims to explain both ideas in a simple way.

Inversion of Control

Basic concepts

Here is an informal definition of IoC: “IoC is when you have someone else create objects for you”. So instead of writing “new MyObject” on your code, the object is created by someone else. This ‘someone else’ is normally referred to as IoC Container.

This simple explanation illustrates some very important ideas:

it is called IoC because the control upon the object is inverted, it is not the programmer but someone else who controls the object.

IoC is relative in the sense that it only applies to some objects of the application. So there may be IoC for some objects whereas others are under the direct control of the programmer.

Apart from Spring, there are other examples of IoC like Java Servlets and Akka Actors.

The details

Let’s delve a little more into the definition of IoC. IoC is much more than object creation: a Spring Context or a Servlet Container not only do create objects but manage their entire life cycle. That includes creating objects, destroying them and invoking certain methods of the object at different stages of its life cycle. These methods are often described as callbacks. Notice again the terminology: methods invoked by the container are callbacks as opposed to the direct calls that programmers make on their own code.

Another thing to consider is that, although programmers relinquish their control on the objects, they still need to define the templates used by the IoC container to create said objects.

For instance, in Spring, classes are annotated with @Service or @Component (among many others) to indicate that the Spring Container is to manage the instances of those classes (it is also possible to use XML configuration instead of annotations). Spring managed objects are called Beans.

In a Servlet application, any class implementing the Servlet interface will be managed by the Servlet Container.

In an Akka application, the IoC container is called ActorSystem and the managed objects are instances of classes extending the trait Actor and created through configuration objects called Props.

Here is a quick summary of the ideas discussed so far:

IoC Containers control and manage the life cycle of some objects: creation, destruction and callback invocations.

The programmer must identify the classes whose instances are to be managed by the IoC Container. There are several ways to do this: with annotations, by extending some specific classes, using external configuration.

The programmer can influence, to some extent, the way the objects are managed by the IoC Container. Normally, this is achieved by overriding the default behaviour of the object callbacks.

IoC Container

Managed Objects Name

Managed Objects Definition

Spring Container

Bean

Classes defined with annotations/XML configuration

Servlet Container

Servlet

Classes implementing interface Servlet

Actor System

Actor

Classes extending trait Actor

So far, we have managed to explain IoC without needing to talk about Dependency Injection.

Dependency Injection

Dependency Injection has become one of the cornerstones of modern Software Engineering as it is fundamental to allow proper testing. To put it simple, having DI is the opposite to having hardcoded dependencies.

A dependency can be injected in several ways like a parameter in the constructor or through a “set” method.

As important as DI is, there is a downside to its use, namely: management of dependencies is inconvenient. Let’s take a look at an example: MyClass1 depends on MyClass2, that in turns depends upon MyClass3:

Although the situation described in this example is not too bad, real-life applications can have hundreds of dependencies scattered all across the codebase whose creation and management would need to be centralised like in the above example.

Inversion of Control and Dependency Injection playing together

We just discussed the issue of managing hundreds of dependencies in a real-life application, possibly with very complicated dependency graphs.

So here is where IoC comes to the rescue. With IoC, the dependencies are managed by the Container and the programmer is relieved of that burden.

Using annotations like @Autowired, the Container is asked to inject a dependency where it is needed, and the programmers do not need to create/manage those dependencies by themselves.

is doing dependency injection, and inversion of control without doing dependency inversion, and unless this is a test it’s code smell, in Spring 4.2+ you should write this (4+ you can, put @Autowired on the constructor), at that point you could create this class by hand in a test or let spring manage it.

Thank you for your comment.
Agreed, it is preferable to annotate the constructor instead of the attributes. I just wanted to make a point of how the use of the annotations could greatly simplify the amount of code necessary to inject the dependencies.