Dependency injection in Spring - practical introduction

Dependency injection in Spring - practical introduction

ยท

4 min read

In this article, we will explain the concept of Dependency Injection(DI) practically and show how to use it in your code with Spring Framework.

Introduction

Dependency injection is one of the two main functionalities of Spring apart from Inversion of Control.

Properly, Dependency Injection(DI) is the implementation of the Inversion of Control principle and is handled by Inversion of Control Container in Spring.

Probably, it is the most important element of Spring infrastructure.

The loose-coupling principle

DI is also a principle that makes it possible to keep the loose-coupling rule of programming.

The Loose-coupling principle is significant in modern systems because it provides better conditions for implementing changes in our software.

Definition

Dependency Injection(in short - DI) is a design pattern, where objects do not initialize their dependencies on their own but accept them from the outside through the "injection".

The reason why this kind of way of initializing objects is right is the fact that among others, it is easier to write unit tests.

DI is a pattern that realizes the IoC principle.

In DI pattern, dependencies are initialized by framework if we talk about Spring for example.

Explanation

DI is about passing a dependent object in a similar way to passing parameters to a method, rather than using a method to create the dependent object.

Below is an explanation based on code examples:

Traditional approach

If we want to create an object in class we use new keyword:

new ConcreteImpl();

Here is a full example of using an object in another class:

public class Book {
    private Cover cover;

    public Book() {
        cover = new CrimeBookCover();    
    }
}

In the example above, while initializing we must decide on the concrete implementation of the Cover class.

There is possibility that we have cover for:

  • Crime's book cover
  • Tutorial's book cover
  • Children's book cover

The main disadvantage of this approach is the fact, that we must choose only one implementation at the code level, so in the future, it will be hard to make changes in the whole software.

We can not pass another implementation of the Cover class(interface or abstract class) in the constructor. The code is not loose-coupled! It is definitely tight-coupled.

There is a better way to solve this kind of problem.

Dependency injection approach

By using DI, we can change the code to form, where we do not specify the concrete implementation of the Cover object.

public class Book {
    private Cover cover;

    public Book(Cover cover) {
        this.cover = cover;
    }
}

In the next paragraphs, we will look at other ways of preserving Dependency Injection pattern.

Dependency Injection in Spring

In this article, we are touching only the basic ways of providing DI in Spring. In the next, I will introduce a wider range of possibilities associated with DI and Spring.

Three types of Dependency Injection(DI)

Currently, using Spring's container there is no reason to think about DI, because Spring will do it for us, in a few, simple ways.

There are three the most common types of DI:

  • constructor injection
  • method(setter) injection
  • property(field) injection

These kinds of bindings are executed using annotation @Autowired

Constructor injection

If we want to inject dependency in the constructor, we have to add @Autowired annotation above the constructor.

public class Book {
    private Cover cover;

    @Autowired
    public Book(Cover cover) {
        this.cover = cover;
    }
}

Method(setter) injection

If we want to inject dependency in a setter, we have to add @Autowired annotation above the method. Setter injection is rarely used and not recommended by Spring creators, but it is worth knowing, that there is something like this.

public class Book {
    private Cover cover;

    @Autowired
    public void setCover(Cover cover) {
        this.cover = cover;
    }
}

Property(field) injection

If we want to inject dependency in a property, we have to add @Autowired annotation above the property.

public class Book {
    @Autowired
    private Cover cover;

    public Book() {}
}

Conclusion

As we can see, DI is not so difficult. I hope that my explanation was enough to understand(if no - DM me or just write a comment, if yes - you could do the same ;) ).

The most important thing to remember is that the biggest advantage of using DI pattern is achieving loose-coupled code and making it easier to test.

The next article will be connected with Dependency Injection but in the context of Spring's Beans and more advanced concepts.

ย