Dependency Injection(DI) is a design pattern that removes the dependency from the programming code so that it can be easy to manage and test the application. This approach allows objects to define their dependencies through some predefined ways only that includes using the constructors, setter methods, primitive values, etc so as to minimize the dependencies among the objects within the class definition. Dependency Injection makes our programs loosely coupled and easy to test. Before understanding DI in a better way, we need to understand Dependency Lookup first.
Dependency Lookup-
DL is an approach where we get the resource after demand. There can be several possible ways to get a resource on demand for example-
A obj = new AImpl();
Here, we’re getting the resource ie. instance of A class directly using the new keyword.
There is another way to do that by using the factory method-
A obj = A.getA();
Concerns with Dependency Lookup
A couple of major issues that we observe while using Dependency Lookup are-
- Tight coupling- This approach makes the code tightly coupled. If we need to change the resource, a lot of modifications are required to be made in the code.
- Not easy to test- This approach creates a lot of problems, especially while testing the application in the black box testing environment.
Dependency Injection is a solution here as it makes the code loosely coupled by removing the dependency of the objects. In such cases, the information is provided from some external resources such as an XML file, Configuration annotated class, etc. An example of this can be-
public class Address{
private String addressLine1, city, state, country;
//getters and setters
public String toString(){
return addressLine1 + " " + city + " " + state + " " + country;
}
}
public class Employee{
private Address address;
private String name;
public Employee(Address address){
this.address = address;
}
public void setAddress(Address address){
this.address = address;
}
}
In the above example, we are not creating the instance of the Address class inside the Employee class rather the instance is being injected/provided by some external source either through the constructor or the setter method. Hence, there are three different methods to inject dependency in a class in Spring Framework-
- By Constructor
- By Setter method
- By field
Constructor-based dependency injection-
Here, the dependency is injected by the constructor where the spring container invokes the constructor having arguments and looks up for the dependencies it needs to set. This can be done in two ways.
The first two methods can be used to inject primitive and String-based values(int, char, String, etc.), a dependent object, and Collection values(List, Map, Set, etc.) whereas the third one works only with the references.
- The first approach is to create a Configuration class that defines and configures the beans and their dependencies using annotations-
@Configuration
public class Config{
@Bean
public Employee employee(){
return new Employee(getAddress());
}
@Bean
public Address getAddress(){
{
return new Address();
}
}
The Configuration notation(@Configuration) is applied to the class which is responsible for providing beans definitions. There can be multiple configuration classes defined with this annotation.
To define a bean, @Bean notation is used on a method. Each bean comes with a scope default being Singleton where only a single bean is created per each Spring IoC container. So, in this case, if there is already a cached version of beans available, the container will return the same else it would create a new bean instance for each method call. - Another approach is to define the configuration of the beans through XML for which applicationContext.xml file is used-
<bean id="adr" class="com.myApp.Address"></bean>
<bean id="emp" class="com.myApp.Employee">
<constructor-arg>
<ref bean="adr">
</constructor-arg>
</bean>
Setter method based dependency injection-
In Setter-based Dependency Injection, the container would call the setter method after invoking a no-argument constructor or no-argument static factory method to instantiate a bean. Here is an example showing how it can be done through the Configuration class-
@Configuration
public class Config{
@Bean
public Employee employee(){
Employee emp = new Employee();
emp.setAddress(getAddress());
Return emp;
}
@Bean
public Address getAddress(){
{
return new Address();
}
}
As it can be seen, the Address bean is being injected into the Employee bean through the setter method.
The process of DI through the setter method using the XML can be done as shown below-
<bean id="adr" class="com.myApp.Address"></bean>
<bean id="emp" class="com.myApp.Employee">
<property name="address" ref="adr" ></property>
</bean>
Field-based Dependency Injection-
Field-based Dependency Injection is the simplest way to inject a dependency, however, due to its drawbacks, it’s usually not recommended. This type of dependency only works with the references and can’t be used to inject the primitive and String-based values. Additionally, this leads to the tight coupling of the bean with its DI container, hence can’t be used outside of that container. Also, field-based DI can’t be used to assign the dependencies on the fields that are set as Final.
In the following basic example, a bean is injected into a reference variable using the @Autowired annotation-
A.java
public class A{
public A (){
System.out.println("A is created");
}
public void show(){
System.out.println("Hello A");
}
}
B.java
public class B{
@Autowired
private A a;
public B(){
System.out.println("B is created");
}
//getter and setter of A
public void show(){
System.out.println("Hello B");
}
}
applicationContext.xml
<bean id="a" class="com.myApp.A"></bean>
<bean id="b" class="com.myApp.B" autowire= “byName”></bean>
If you need to prove your skills in the .NET framework, get .NET certified on StudySection. StudySection provides .NET certification exam for beginners as well as experts in the .NET framework. This .NET certification can improve your resume’s success rate.