Overview
As a developer, we trend to create modular and loosely coupled applications. To accomplish modularity developer divided the application into multiple classes and each class depends on one or more other classes to accomplish desired functionality in an application. Spring is the most popular dependency injection framework for Java.
Let take an example to understand the dependency. A person has a name. It also means 'Person' has a dependency on 'Name'.
public class Person {
private Name personName;
}
To accomplish independence from other dependent classes Spring framework provides Inversion of Control (IoC) which is basically inverting the dependency injection flow. In IoC, Spring container inject those dependencies when it creates the beans. We will now see how to define this bean and inject the dependent object in it.
Type of dependency injection
Primarily there are two types of dependency injection
1. Constructor-based dependency injection
2. Setter-based dependency injection
Constructor-based dependency injection
Constructor-based dependency injection is accomplished by constructor arguments where each argument represents the dependency.
package example;
public class Person {
private Name personName;
// Dependency injected via argument by Spring
public Person(Name personName){
this.personName = personName;
}
}
Spring Bean Definition
<bean id="personName" class="example.Name" />
<bean id="constructorExample" class="example.Person">
<constructor-arg type="example.Name" ref="personName" />
</bean>
Constructor based injection using static factory method
package example;
public class PersonFactory {
public static Person createPerson(Name personName){
return new Person(personName);
}
}
Spring Bean Definition
<bean id="personName" class="example.Name" />
<bean id="person" class="example.PersonFactory"
factory-method="createPerson">
<constructor-arg ref="personName" />
</bean>
Setter-Based Dependency injection
Setter-based dependency injection is accomplished by calling the Java bean write method (i.e. setter) on object which is created using no-argument constructor or no-argument static factory method.
public class Person {
private Name personName;
// Setter method so that Spring can inject the dependency
public void setPersonName(Name personName){
this.personName = personName;
}
}
Spring Bean Definition
<bean id="personName" class="example.Name" />
<bean id="setterExample" class="example.Person">
<property name="personName" ref="personName" />
</bean>
Setter based injection using static factory method
package example;
public class Person {
private Name personName;
private Person(){
}
// Factory method
public static Person createPerson(){
return new Person();
}
private void setPerson(Name personName){
this.personName = personName;
}
}
Spring Bean Definition
<bean id="personName" class="example.Name" />
<bean id="person" class="example.Person"
factory-method="createPerson">
<property name="personName" ref="personName" />
</bean>
So, where to use constructor-based and when to use setter-based ?
Constructor based injection is recommended when we want dependencies to be injected during creation of object. In other words if dependency is absolutely mandatory then we will use constructor, and if dependency is option then we could use setter based injection.
Now what if during first phase of development, dependency was optional so we used setter based injection but now due to change in requirement dependency is mandatory. To deal with this kind of scenario Spring provide an annotation @Required which actually enforce that setter based dependency must be populated during bean creation otherwise it will raise BeanInitializationException exception.
public class Person {
private Name personName;
// Setter method so that Spring can inject the dependency
@Required
public void setPersonName(Name personName){
this.personName = personName;
}
}
Spring Bean Definition
<bean id="personName" class="example.Name" />
<bean id="setterExample" class="example.Person">
<!-- Not injecting setter based dependency -->
<!--property name="personName" ref="personName" / -->
</bean>
Exception message will be printed as "Property 'personName' is required for bean 'setterExample'".
So technically developers need to take decision based on their business requirement which type need to use.