Enterprise Java

Spring Dependency Injection – Field vs Setter vs Constructor Injection

Welcome to 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 of them and why to chose one over the other.

More on Spring Dependency Injection:

Overview

In the Spring Framework, the Dependency Injection comes in three types. Those are Field Injection, Setter Injection and Constructor Injection. You can absolutely use any of them and they result into exactly the same outcome. However, based on ease, readability, coding standards or better coding practices there are few differences. Before we jump into see what those differences are, very quickly, we will see all three types of Dependency Injections in action.

Field Based Dependency Injection

01
02
03
04
05
06
07
08
09
10
11
12
13
@Component
public class MyClass {
 
    @Autowired private DogsController controller;
    @Autowired private DogsService service;
    @Autowired private DogsDao dao;
    @Autowired private ApplicationProperties properties;
 
 
    //...
    // Business methods
    //
}

Setter Based Dependency Injection

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@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;
    }
 
 
    //...
    // Business methods
    //
}

Constructor Based Dependency Injection

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
@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;
    }
 
    //...
    // Business methods
    //
}

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

Readability

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

Lets apply readability measure to all three of them

  • Field Injection: The Best. Less boilerplate code. Focus is on business logic.
  • Constructor Injection: Better. Constructors visually stand separate from methods.
  • Setter Injection: Worst. Added 4 instance methods. Takes away focus form business methods.

Immutability

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

If we look at the above examples, in 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 to the instantiaters so that they will invoke the object in a correct state. If the Object doesn’t mandate such state safety, there is a possibility of the objects 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 initialise all the fields, those are part of @Autowired. But some consumer may instantiate your object with a new keyword. We should look at state safety beyond Spring Framework.

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

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

Too Many Instance Fields

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

Field Injection: Still looks better, and readable. The dependency part is segregated at one place.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
@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;
     
    //...
    // Business methods
    //
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@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;
    }
 
 
//...
    // Business methods
    //
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@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;
    }
 
    //...
    // Business methods
    //
}

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 is an indication of something is just isn’t right about 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 case of ‘Too Many Instance Fields’.

In exceptional scenarios, where having too many fields is unavoidable, and ugly constructor is kind of 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 of the 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 and not rules. You just be smart enough to take a call and justify which way you want to go.

Happy Coding !!

Published on Java Code Geeks with permission by Amit Phaltankar, partner at our JCG program. See the original article here: Spring Dependency Injection – Field vs Setter vs Constructor Injection

Opinions expressed by Java Code Geeks contributors are their own.

Amit Phaltankar

Amit Phaltankar is a Technology enthusiast who has huge passion for sharing what he knows. Amit works as a Java Technology Lead and has huge experience in Programming, Unit Testing, OOAD, Functional Programming, Big Data Technologies, micro-services, and Databases.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Mark Nuttall
Mark Nuttall
5 years ago

Don’t forget that with the current version of Spring, if a Spring managed class has a single Constructor, Spring will Autowire it for you without needing to add @Autowired.

And if you use Lombok (or something similar) you don’t even have to write the constructor.

Binh Thanh Nguyen
Binh Thanh Nguyen
4 years ago

Thanks, nice explanation

Alexander Orlov
Alexander Orlov
2 years ago

You can make setter injection more readable with lombok:

@Setter(onMethod_ = @Autowired)
private Service1 service1;

Back to top button