When it comes to Spring specific pros and cons:
Constructor injection (from the definition) does not allow you to create circular dependencies between beans. This limitation is actually an advantage of constructor injection - Spring can resolve circular dependencies when setter injection is used without you even noticing.
On the other hand if you use constructor injection CGLIB is not able to create a proxy, forcing you to either use interface-based proxies or a dummy no-arg constructor. See: SPR-3150
A well explained article on 'When to use Constructor Injection vs. Setter Injection?'
java - Explain why constructor inject is better than other options - Stack Overflow
Choosing between field injections and constructor injections for modular Java applications with Spring Boot - Code Review Stack Exchange
When to use Constructor Injection vs. Setter Injection
Constructor injection vs Field injection
Videos
When it comes to Spring specific pros and cons:
Constructor injection (from the definition) does not allow you to create circular dependencies between beans. This limitation is actually an advantage of constructor injection - Spring can resolve circular dependencies when setter injection is used without you even noticing.
On the other hand if you use constructor injection CGLIB is not able to create a proxy, forcing you to either use interface-based proxies or a dummy no-arg constructor. See: SPR-3150
You should be deciding based on design considerations, not tool (Spring) considerations. Unfortunately, Spring has trained us to use setter injection because when it was originally conceived, there was no such thing as an "annotation" in Java, and in XML, setter injection works and looks much better. Today, we're freed from those constraints, thus allowing it to be a design decision again. Your beans should use constructor injection for any dependencies that are required by the bean and setter injection for dependencies that are optional and have a reasonable default, more or less as OOD has been telling us from the beginning.
A class that takes a required dependency as a constructor argument can only be instantiated if that argument is provided (you should have a guard clause to make sure the argument is not null) (or use a non-nullable type in Kotlin). A constructor therefore enforces the dependency requirement whether or not you're using Spring, making it container-agnostic.
If you use setter injection, the setter may or may not be called, so the instance may never be provided with its dependency. The only way to force the setter to be called is using @Required or @Autowired
, which is specific to Spring and is therefore not container-agnostic.
So to keep your code independent of Spring, use constructor arguments for injection. This applies to tests; you'll have an easier time instantiating and testing the class in a normal unit test, without needing to configure an application context or the complexity that comes along with setting up an integration test.
Update: Spring 4.3 will perform implicit injection in single-constructor scenarios, making your code more independent of Spring by potentially not requiring an @Autowired annotation at all.
(...) by using Constructor Injection, you assert the requirement for the dependency in a container-agnostic manner
This mean that you can enforce requirements for all injected fields without using any container specific solution.
Setter injection example
With setter injection special spring annotation @Required is required.
@Required
Marks a method (typically a JavaBean setter method) as being 'required': that is, the setter method must be configured to be dependency-injected with a value.
Usage
import org.springframework.beans.factory.annotation.Required;
import javax.inject.Inject;
import javax.inject.Named;
@Named
public class Foo {
private Bar bar;
@Inject
@Required
public void setBar(Bar bar) {
this.bar = bar;
}
}
Constructor injection example
All required fields are defined in constructor, pure Java solution.
Usage
import javax.inject.Inject;
import javax.inject.Named;
@Named
public class Foo {
private Bar bar;
@Inject
public Foo(Bar bar) {
this.bar = bar;
}
}
Unit testing
This is especially useful in Unit Testing. Such kind of tests should be very simple and doesn't understand annotation like @Required, they generally not need a Spring for running simple unit test. When constructor is used, setup of this class for testing is much easier, there is no need to analyze how class under test is implemented.
You can refer to the official documentation of Spring, section "Constructor-based or setter-based DI?", it says"
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Autowired annotation on a setter method can be used to make the property be a required dependency; however, constructor injection with programmatic validation of arguments is preferable.
The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.
Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.
Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.
First, I don't know Spring and I'm proud, so there may be some Spring-specific reasons to chose one of these styles, that I'm not aware of.
In terms of pure dependency injection however, usually constructors are a better choice, as this way your components remain more abstract from the point of view of dependency-injection framework. That is, when using field/setter injection, the framework needs to analyse in detail full structure of your components (using reflection) to find all fields/setters it needs to inject (in case of constructor injection it only needs to get the param list of a given constructor).