Spring Dependency Injection – Field vs Setter vs Constructor Injection

Welcome to the Spring Dependency Injection – Field vs Setter vs Constructor Injection tutorial. Learn the difference between Field Injection, Setter Injection and Constructor Injection. With the help of code examples, we will see the benefits of using each and why to choose one over the other.

Overview

In the Spring Framework, the Dependency Injection comes in three types. These are Field Injection, Setter Injection and Constructor Injection. You can use any of them, resulting in the same outcome. However, there are a few differences based on ease, readability, coding standards or better coding practices.

Before we see what those differences are, we will see all three types of Dependency Injections in action.

Field Based Dependency Injection

Example of a Field Injection.

@Component
public class MyClass {

  @Autowired private DogsController controller;
  @Autowired private DogsService service;
  @Autowired private DogsDao dao;
  @Autowired private ApplicationProperties properties;
  // Skipped
}Code language: Java (java)

Setter Based Dependency Injection

Example of Setter Injection.

@Component
public class MyClass {

  private DogsController controller;
  private DogsService service;
  private DogsDao dao;
  private ApplicationProperties properties;

  @Autowired
  public void setController(DogsController controller) {
    this.controller = controller;
  }

  @Autowired
  public void setService(DogsService service) {
    this.service = service;
  }

  @Autowired
  public void setDao(DogsDao dao) {
    this.dao = dao;
  }

  @Autowired
  public void setProperties(ApplicationProperties properties) {
    this.properties = properties;
  }
  // Skipped
}Code language: Java (java)

Constructor Based Dependency Injection

Example of Constructor Injection.

@Component
public class MyClass {

  private DogsController controller;
  private DogsService service;
  private DogsDao dao;
  private ApplicationProperties properties;

  @Autowired
  public MyClass(DogsController controller, 
      DogsService service, DogsDao dao, 
      ApplicationProperties properties) {

    this.controller = controller;
    this.service = service;
    this.dao = dao;
    this.properties = properties;
  }

  //Skipped
}Code language: Java (java)

We have code references for all three types of Dependency Injections. Let’s evaluate them on some critical aspects of Object Oriented Design principles.

Readability

Readability is humans’ judgement about how easy to understand a software program or a piece of software program is. Developer spends 30% of their time writing software and 70% of their time maintaining it. The readability improves software maintainability. When a developer looks at a class, they should quickly be able to focus on vital parts of the class without getting distracted by boilerplate code or other framework components.

Let’s apply the readability measure to all three of them

  • Field Injection: The Best. Less boilerplate code. The focus is on business logic.
  • Constructor Injection: Better. Constructors visually stand separate from methods.
  • Setter Injection: Worst. When we have a large number of fields, the setter methods cause a focus shift.

Immutability

In Software Programming terms, an Object is called Immutable if, by any means, its state can not be modified after creation. Immutability is a really important principle of good Object Oriented Programming. The immutability brings thread safety, state safety, and readability to the classes.

If we look at the above examples from an immutability perspective.

  • Constructor Injection: Supports immutability.
  • Setter Injection: No immutability.
  • Field Injection: No immutability.

State Safety

An object, most likely, is instantiated by the consumers or the underlying framework. The object itself should provide rules or guidelines for its instantiation. If the object doesn’t mandate such state safety, there is a possibility of the object being instantiated to incomplete or incorrect states.

Note: All of the above examples are state safe because Spring is resolving their dependencies, and Spring will correctly initialize all the fields that are part of the @Autowired. But some consumers may instantiate your object with the new keyword. We should look at state safety beyond Spring Framework.

Let’s apply the State Safety measure to all the examples we saw.

  • Constructor Injection: State Safe. The object is instantiated to the entire state or is not instantiated at all.
  • Setter Injection: The consumer uses a no-argument constructor. And possibly miss calling one of the setters or call the same setter twice with a different value (copy-paste bugs)
  • Field Injection: Consumer uses no-argument constructor. There is no valid way to set the state of the object. The only option is to use Reflection to set the private fields.

Too Many Instance Fields

Let’s consider a case of Objects having 6, 7 or more fields. What happens when you use the above examples with many fields?

The Field-based dependency injection still looks better and more readable. The dependency part is segregated in one place.

@Component
public class MyClass {

  @Autowired private Service1 service1;
  @Autowired private Service2 service2;
  @Autowired private Service3 service3;
  @Autowired private Service4 service4;
  @Autowired private Service5 service5;
  @Autowired private Service6 service6;
  @Autowired private Service7 service7;
  @Autowired private Service8 service7;
    
  //Skipped
}Code language: Java (java)

Constructor Injection: Ugly !! The constructor injection is looking ugly. It is also not easy to use for consumers.

@Component
public class MyClass {

  private Service1 service1;
  private Service2 service2;
  private Service3 service3;
  private Service4 service4;
  private Service5 service5;
  private Service6 service6;
  private Service7 service7;
  private Service8 service7;

  @Autowired
  public MyClass(Service1 service1, 
      Service2 service2, Service3 service3, 
      Service4 service4, Service5 service5, 
      Service6 service6, Service7 service7, 
      Service8 service71) {
    this.service1 = service1;
    this.service2 = service2;
    this.service3 = service3;
    this.service4 = service4;
    this.service5 = service5;
    this.service6 = service6;
    this.service7 = service7;
    this.service7 = service71;
  }


  //Skipped
}Code language: Java (java)

Setter Injection: Bad. It has added eight extra instance methods just for setting up the dependency.

@Component
public class MyClass {

  private Service1 service1;
  private Service2 service2;
  private Service3 service3;
  private Service4 service4;
  private Service5 service5;
  private Service6 service6;
  private Service7 service7;
  private Service8 service7;

  @Autowired
  public void setService1(Service1 service1) {
    this.service1 = service1;
  }

  @Autowired
  public void setService2(Service2 service2) {
    this.service2 = service2;
  }

  @Autowired
  public void setService3(Service3 service3) {
    this.service3 = service3;
  }

  @Autowired
  public void setService4(Service4 service4) {
    this.service4 = service4;
  }

  @Autowired
  public void setService5(Service5 service5) {
    this.service5 = service5;
  }

  @Autowired
  public void setService6(Service6 service6) {
    this.service6 = service6;
  }

  @Autowired
  public void setService7(Service7 service7) {
    this.service7 = service7;
  }

  @Autowired
  public void setService7(Service8 service7) {
    this.service7 = service7;
  }
  //Skipped
}Code language: Java (java)

Should we Even Consider ‘Too Many Instance Fields’?

With the Too Many Instance Fields check, we found the Field Injection the best. The real question is, Should we even give importance to the too many fields issue?

The answer is NO.
We all love and follow Single Responsibility Principle. If your class depends on too many things, it indicates something wrong with the design. With better designs, you won’t see these problems. We should discourage supporting bad design cases. Hence, we won’t give importance to the point of ‘Too Many Instance Fields’.

In exceptional scenarios, where having too many fields is unavoidable, and an ugly constructor is a big issue, you should take a call and go for Field Injection.

Conclusion

Based on the above code examples and the facts, it is clear that Construction Based Dependency Injection consistently stands better in all cases. Even if we look at our class beyond the perspective of Spring Dependency Injection, the Constructor Injection is still the best option.

Note: All the Design Principles, or Better Coding standards and the things we discussed here are just guidelines, not rules. You be smart enough to take a call and justify which way you want to go.