Understanding Dependency Injection by writing a DI Container - from scratch! (Part 1)
Tags: java, dependencyinjection, spring, jee
Published: 2020-02-11 21:48:15

---
title: Understanding Dependency Injection by writing a DI Container - from scratch! (Part 1)
published: true
description: Dependency Injection is a difficult topic to grasp. Let's break it down into simple pieces by writing a basic, yet fully functional DI container from scratch!
series: DI From Scratch
tags: java, dependency injection, spring, jee
---

Dependency Injection (DI) can be a very difficult topic to grasp, since there seems to be a lot of "magic" going on. Usually it involves a bunch of annotations scattered all over the place, with objects appearing seemingly out of nowhere. I certainly know that it took me a long while to really understand the concept. If you ever find it hard to understand what Spring and Java EE are doing behind the curtains (and why!), read on!

In this tutorial, we are going to build a very bare-bones, yet fully functional dependency injection container **from scratch** in Java. Here are some rules to keep things manageable:

- Absolutely **no libraries** allowed, except for the JDK itself.
- No pre-prepared code dumps. We will go through everything and reason about it.
- No bells & whistles, just the basics.
- Performance doesn't matter, no optimizations.
- Executable `main()` methods at every step.

In contrast to other articles, I will **not** explain up-front what DI is or why it is useful. Instead, we'll start with a simple example and let it "evolve".


# DI Stage 0: Basic example

> Find the source code of this section [on github](https://github.com/MartinHaeusler/blog/tree/master/diFromScratch/src/main/java/org/example/simplecdi/stage0/staticreferences)

We start with a very basic example. We want two classes, let's call them `ServiceA` and `ServiceB`, and `ServiceA` needs `ServiceB` to do its work. Well, you might implement it with `static` methods and be done with it! So here goes:

```java
public class ServiceA {

    public static String jobA(){
        return "jobA(" + ServiceB.jobB() + ")";
    }

}
```

```java
public class ServiceB {

    public static String jobB(){
        return "jobB()";
    }

}
```

```java
public class Main {

    public static void main(String[] args) {
        System.out.println(ServiceA.jobA());
    }
    
}
```

If we run this code, it will print:

```
jobA(jobB())
```

Cool! So why even bother with more than this? Well...
- The code is very poor in terms of OO principles. ServiceA and ServiceB should, at the very least, be *objects*.
- The code is tightly coupled and very hard to test in isolation.
- We have absolutely no chance of swapping neither ServiceA nor ServiceB with a different implementation. Imagine one of them is doing credit card billings; you **don't** want that to actually happen in your test suite.


# DI Stage 1: Getting rid of static references

> Find the source code of this section [on github](https://github.com/MartinHaeusler/blog/tree/master/diFromScratch/src/main/java/org/example/simplecdi/stage1/constructorinjection)

The main problem we identified in Stage 0 is that there are only static methods, resulting in extremely tight coupling. We would like our services to be objects talking to each other, such that we may replace them as needed. Now the question arises: how does ServiceA know *which* ServiceB to talk to? The most basic idea is to simply give our instance of ServiceB to the constructor of ServiceA:

```java
public class ServiceA {

    private ServiceB serviceB;

    public ServiceA(ServiceB serviceB){
        this.serviceB = serviceB;
    }

    public String jobA(){
        return "jobA(" + this.serviceB.jobB() + ")";
    }

}
```

Service B didn't change much:

```java
public class ServiceB {

    public String jobB() {
        return "jobB()";
    }
    
}
```

... and `Main` now needs to assemble the objects before it can call the `jobA` method:

```java
   public static void main(String[] args) {
        ServiceB serviceB = new ServiceB();
        ServiceA serviceA = new ServiceA(serviceB);

        System.out.println(serviceA.jobA());
    }
```

Nothing fancy here, right? We certainly improved some things:
- We can now replace the implementation of `ServiceB` which is used by `ServiceA` by providing another object, potentially even of another subclass.
- We can test both services in isolation with a proper test mock for ServiceA.

So all cool? Not quite:
- It's hard to create mocks, as we require a **class**. 
- It would be much nicer if we required **interfaces** instead. Also, this would further reduce the coupling.

# DI Stage 2: Using interfaces

> Find the source code of this section [on github](https://github.com/MartinHaeusler/blog/tree/master/diFromScratch/src/main/java/org/example/simplecdi/stage2/constructorwithinterfaces)

So let's use one interface for each of our services. They're about as simple as it gets (I renamed the actual classes to `ServiceAImpl` and `ServiceBImpl`, respectively):

```java
public interface ServiceA {

    public String jobA();

}
```

```java
public interface ServiceB {

    public String jobB();

}
```

Now, in `ServiceAImpl`, we can actually use the interface:

```java
public class ServiceAImpl implements ServiceA {

    private final ServiceB serviceB;

    public ServiceAImpl(ServiceB serviceB){
        this.serviceB = serviceB;
    }

    // jobA() is the same as before
}
```

That also makes our `main()` method a bit nicer:

```java
  public static void main(String[] args) {
        ServiceB serviceB = new ServiceBImpl();
        ServiceA serviceA = new ServiceAImpl(serviceB);
        System.out.println(serviceA.jobA());
    }
```

This would be perfectly acceptable for simple use cases from an OO perspective. If you can get away with this, by all means, stop here. However, as your project gets bigger...

- it will become more and more complex to **create the network of services** inside your `main()` method.
- you will encounter **cycles** in your service dependencies which cannot be resolved using constructors as shown in our example.

# DI Stage 3: Breaking the cycle with setters

> Find the source code of this section [on github](https://github.com/MartinHaeusler/blog/tree/master/diFromScratch/src/main/java/org/example/simplecdi/stage3/setters)


Let's assume that not only `ServiceA` needs `ServiceB`, but also the other way around - we have a cycle. Of course, we may still declare a parameter in the constructor of the `*Impl` classes, like so:

```java

 // constructor examples
 public ServiceAImpl(ServiceB serviceB) { ... }
 public ServiceBImpl(ServiceA serviceA) { ... }

```


... but that will do us no good: we will be unable to create an actual **instance** of either of the two classes. To create an instance of `ServiceAImpl`, we would first require an instance of `ServiceB`, and to create an instance of `ServiceBImpl` we first require an instance of `ServiceA`. We're deadlocked.

> Side note: there is actually a way out of this by using **proxies**. However, we're not going to take that route here.

So what do we do instead? Well, since we are dealing with cyclic dependencies, we need the ability to first **create** the services and then **wire** them together. We do this with setters:

```java
public class ServiceAImpl implements ServiceA {

    private ServiceB serviceB;

    // no constructor anymore here!

    @Override // <- added getter to ServiceA interface
    public ServiceB getServiceB() { return serviceB; }

    @Override // <- added setter to ServiceA interface
    public void setServiceB(final ServiceB serviceB) { this.serviceB = serviceB; }

    // jobA() same as before
}
```

Our `main()` method looks like this:

```java
    public static void main(String[] args) {
        // create instances
        ServiceB serviceB = new ServiceBImpl();
        ServiceA serviceA = new ServiceAImpl();

        // wire them together
        serviceA.setServiceB(serviceB);
        serviceB.setServiceA(serviceA);

        // call business logic
        System.out.println(serviceA.jobA());
    }
```

Can you see the pattern? First create the objects, then connect them to form the service graph (i.e. service network).

So why not stop here?
- Doing the wiring part manually is error prone. You might forget to call a setter and then it's `NullPointerException` galore.
- You might accidentally use a service instance that is still under construction, so it would be beneficial to encapsulate the network construction somehow.

# Up next

In the next blog post, we will discuss how we can automate the wiring we are doing manually right now.