In a Pro Spring 3 Book, Chapter 4 - Introduction IOC and DI in Spring - Page 59, In "Setter Injection vs. Constructor Injection" section, a paragraph says
Spring included, provide a mechanism for ensuring that all dependencies are defined when you use Setter Injection, but by using Constructor Injection, you assert the requirement for the dependency in a container-agnostic manner"
Could you explain with examples
Constructor injection helps in creating immutable objects because a constructor's signature is the only possible way to create objects. Once we create a bean, we cannot alter its dependencies anymore.
Setter Injection has upper hand over Constructor Injection in terms of readability. Since for configuring Spring we use XML files, readability is a much bigger concern.
If a dependency is used in only one spot, method injection (covered below) might be a better choice. Constructor injection should be the main way that you do dependency injection. It's simple: A class needs something and thus asks for it before it can even be constructed.
Constructor Injection: State Safe. The object is instantiated to a full state or is not instantiated at all. Field Injection: Consumer uses no-argument constructor. There is no valid way to set state of the object.
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.
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; } }
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; } }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With