Signup/Sign In
LAST UPDATED: NOVEMBER 11, 2021

Spring Dependency Injection (DI) Patterns

    Spring framework provides three types of dependency injections namely field injection, setter injection, and constructor injection. It has always been a hot topic for debate that which dependency injection pattern we should use in our day to day coding practice. Let's dive deeper into each pattern and understand its pros and cons.

    Types of dependency injections in Spring framework:

    1. Field Injection

    2. Constructor Injection

    3. Setter Injection

    So let's cover each of these, one by one, with some sample code examples for each dependency injection pattern.

    Spring DI: Field Injection

    In this type of injection, values are injected into the fields by adding an @Autowired annotation. So, at the time when spring creates the beans and application context, and if it sees any field annotated with @Autowired, it looks into the already created beans, and if any bean matches with it, spring injects it into the field. But if spring doesn't find any such bean then it will not throw any exception and everything will work fine unless we want to use that value.

    Below we have a code example for it:

    @Component
    public class Employee {
     
       @Autowired
       private Company company;
     
       @Autowired
       private Address address;
     
       //remaining fields and methods
    }

    Spring DI: Constructor Injection

    In this type of injection, values are injected into the fields inside the constructor of the class. So, when spring is creating the bean of this class, it must have the beans of the parameters of its constructor otherwise it will not be able to create the bean of the class and will throw an exception. But if it has the beans of the parameters, it injects those into them.

    Below we have a code example for it:

    @Component
    public class Employee {
     
       private Company company;
     
       private Address address;
     
       public Employee(Company company, Address address)
       {
          this.company = company;
          this.address = address;
       }
     
       //remaining fields and methods
    }

    Spring DI: Setter Injection

    In this type of injection, values are injected into the fields by adding an @Autowired annotation on their respective setters. It is similar to the field injection but is more structured and better. So, while creating the bean of the class, if spring finds any bean to inject into the fields using setters, then it does that otherwise doesn't throw any exceptions.

    Below we have a code example for it:

    @Component
    public class Employee {
     
       private Company company;
     
       private Address address;
    
       public Company getCompany() {
          return company;
       }
       public Address getAddress() {
          return address;
       }
     
       @Autowired
       public void setCompany(Company company) {
          this.company = company;
       }
     
       @Autowired
       public void setAddress(Address address) {
          this.address = address;
       }
     
       //remaining fields and methods
    }

    Spring DI Patterns Comparison

    Now let's compare the above given DI patterns on various factors:

    1. Readability:

    Readability is one of the most prominent metrics of how good a particular code is. As soon as we see a code, our focus must go on the main business logic of it and should not be distracted by the boilerplate codes present there.

    In all of the three sample codes present above, field injection provides us the most readable code. Constructor injection also has good readability as it is separately present in comparison to the setter injection. Setter injection provides poor readability as it adds a lot of boilerplate codes in our application. So in this metric, field injection seems to be better than others.

    2. Single Responsibility Principle:

    Single responsibility principle or separation of concerns is a principle widely followed and appreciated in the programming community. Each class must handle a single responsibility or concern and it helps in the better and easy maintainability of our whole application.

    In the case of field injection, we can see that it is very easy to add more and more properties (dependencies). Being so easy and simple, we sometimes end up adding too many dependencies in our class without getting a red flag that we might be violating the single responsibility principle (separation of concerns). On the other hand, Constructor injection raises a red flag whenever we end up adding too many dependencies in our class as our constructor will contain too many arguments and look dirty in such a case. Similarly, setter injection will end up adding too many setters for each dependency. So in this metric, constructor and setter injections are better than field injection.

    3. Immutability:

    In the software industry, an object is said to be immutable if, after creation, its state can not be modified by any means. Immutability is considered to be a good Object Oriented programming principle and we should try to adhere to it, whenever possible. Among the given three dependency injection patterns, only constructor injection provides immutability as the constructor is invoked only when the object of that class is being created. So in this metric, constructor injection seems to be better than the others.

    4. Coupling with Dependency Injection container:

    The main aim of dependency injection is to provide loose coupling among the classes of our application. Also, every DI pattern aims that the classes should have no dependency on the DI container and should be loosely coupled with it. But in the case of field injection, it causes tight coupling between the class and DI container.

    But the good programming methodology says that a class must be independent and a simple POJO which can be instantiated even without a DI container by providing the required dependencies like while testing is a good approach. Loose coupling also allows to easily replace the DI framework with some other new framework in the future. So if we compare the given three DI injection patterns, field injection is the worst as it is tightly coupled with DI container. Setter injection is better but still, we require to add @Autowired annotation in our code. Constructor injection is best in this case as we don't even require to add @Autowired annotation in our code.

    (Good Read: Implicit constructor injections for single constructor scenarios after spring 4.0)

    5. Circular dependency:

    If object A is dependent on object B for its creation and object B is dependent on object A for its creation then there's a circular dependency between them. It can exist among 3 or more inter-dependent classes too. If a circular dependency exists in your application then it is a sign of bad programming design and it must be avoided.

    If we are using constructor injection and circular dependency exist in our application, then BeanCurrentlyInCreationException exception will occur as both objects require each other for their creation through constructors.

    While in field and setter injection, spring doesn't throw any such exception as in these injections, dependencies are injected only after the objects are created. So, in case if circular dependency is mandatory in your application, use setter or field injection, Otherwise use constructor injection. Here's a simple example of circular dependency explained above.

    Here's the class A dependent on class B:

    @Component
    public class A {
         @Autowired
         B b;
    }

    and here's the class B dependent on class A:

    @Component
    public class B {
        @Autowired
        A a;
    }

    Conclusion:

    We should avoid using field injection as it only provides better readability over so many drawbacks as discussed above.

    Setter and Constructor injections have their own pros and cons as discussed above. So we should use the combination of both which is also suggested by the Spring community itself.

    Use constructor injection for the mandatory dependencies and setter injection for optional dependencies. (Here mandatory dependency is the one without which the main business logic wouldn't work and optional dependencies are the ones which if null doesn't hamper the main business logic).

    You may also like:

    I'm a writer at studytonight.com.
    IF YOU LIKE IT, THEN SHARE IT
    Advertisement

    RELATED POSTS