Spring Dependency Injection
Dependency Injection is the main functionality provided by Spring IOC(Inversion of Control). The Spring-Core module is responsible for injecting dependencies through either Constructor or Setter methods. The design principle of Inversion of Control emphasizes keeping the Java classes independent of each other and the container frees them from object creation and maintenance. These classes, managed by Spring, must adhere to the standard definition of Java-Bean. Dependency Injection in Spring also ensures loose coupling between the classes.
Need for Dependency Injection:
Suppose class One needs the object of class Two to instantiate or operate a method, then class One is said to be dependent on class Two. Now though it might appear okay to depend on a module on the other, in the real world, this could lead to a lot of problems, including system failure. Hence such dependencies need to be avoided. Spring IOC resolves such dependencies with Dependency Injection, which makes the code easier to test and reuse .
Loose coupling between classes can be possible by defining interfaces for common functionality and the injector will instantiate the objects of required implementation. The task of instantiating objects is done by the container according to the configurations specified by the developer.
Types of Spring Dependency Injection
There are two primary types of Spring Dependency Injection:
1. Setter Dependency Injection (SDI):
Setter DI involves injecting dependencies via setter methods. To configure SDI, the @Autowired annotation is used along with setter methods, and the property is set through the <property> tag in the bean configuration file.
package com.geeksforgeeks.org;
import com.geeksforgeeks.org.IGeek;
import org.springframework.beans.factory.annotation.Autowired;
public class GFG {
// The object of the interface IGeek
private IGeek geek;
// Setter method for property geek with @Autowired annotation
@Autowired
public void setGeek(IGeek geek) {
this.geek = geek;
}
}
Bean Configuration:
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="GFG" class="com.geeksforgeeks.org.GFG">
<property name="geek">
<ref bean="CsvGFG" />
</property>
</bean>
<bean id="CsvGFG" class="com.geeksforgeeks.org.impl.CsvGFG" />
<bean id="JsonGFG" class="com.geeksforgeeks.org.impl.JsonGFG" />
</beans>
This injects the CsvGFG bean into the GFG object using the setter method (setGeek).
2. Constructor Dependency Injection (CDI):
Constructor DI involves injecting dependencies through constructors. To configure CDI, the <constructor-arg> tag is used in the bean configuration file.
package com.geeksforgeeks.org;
import com.geeksforgeeks.org.IGeek;
public class GFG {
// The object of the interface IGeek
private IGeek geek;
// Constructor to set the CDI
public GFG(IGeek geek) {
this.geek = geek;
}
}
Bean Configuration:
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="GFG" class="com.geeksforgeeks.org.GFG">
<constructor-arg>
<bean class="com.geeksforgeeks.org.impl.CsvGFG" />
</constructor-arg>
</bean>
<bean id="CsvGFG" class="com.geeksforgeeks.org.impl.CsvGFG" />
<bean id="JsonGFG" class="com.geeksforgeeks.org.impl.JsonGFG" />
</beans>
This injects the CsvGFG bean into the GFG object via the constructor.
Example of Spring DI:
We have used three classes and an interface as beans to exemplify the concepts of CDI and SDI. They are Vehicle, ToyotaEngine, Tyres classes and IEngine interface respectively.
From our example, we can see that class Vehicle depends on the implementation of the Engine, which is an interface. (So, basically, a Vehicle manufacturer wants a standard Engine which complies to Indian emission norms.) Class ToyotaEngine implements the interface and its reference is provided in the bean-configuration file mapped to one of Vehicle class's properties.
In the Vehicle class, we invoke the application context and bean instantiation is executed. Two objects of class Vehicle are instantiated. 'obj1' is instantiated via bean with name InjectwithConstructor . The bean name could be located in the bean configuration file. Similarly 'obj2' is instantiated via bean with name InjectwithSetter .
It can be observed that 'obj1' is injected via the constructor and 'obj2' uses setter injection.
In the bean configuration file below, we have used two Vehicle beans' declarations.
InjectwithConstructor bean makes use of element constructor-arg, with attributes name and ref. 'Name' attribute correlates with the constructor argument name given in the Vehicle class definition. And 'ref' attribute points to the bean reference which can be used for injecting.
InjectwithSetter makes use of property element to provide the 'name' of the property and the 'value' for the property. In place of value attribute 'ref' can be used to denote a reference to a bean.
In the configuration details, we are injecting ToyotaBean reference into the IEngine reference in Vehicle class constructor-arg, where IEngine is an interface and needs an implementing class reference for bean injection.
We have used two separate bean references for Tyres class, to inject via setter and constructor respectively. We can observe that 'tyre1Bean' and 'tyre2Bean' are initialized with String literal values for each of the properties.