Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Explain why constructor inject is better than other options [duplicate]

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

like image 637
minil Avatar asked Jan 19 '14 15:01

minil


People also ask

Why is constructor injection better?

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.

Which is better constructor injection or setter injection?

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.

Which dependency injection method is better?

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.

What is the difference between constructor injection and field injection?

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.


2 Answers

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.

like image 78
Emerson Farrugia Avatar answered Oct 12 '22 23:10

Emerson Farrugia


(...) 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.

like image 31
MariuszS Avatar answered Oct 12 '22 23:10

MariuszS