In a well-designed Java application, the classes should be as independent as possible. Such a design promotes reusability of components. It also makes it easier to unit test the various components.
The concept of dependency injection promotes loose coupling among Java objects.
In this tutorial, we’ll talk about the dependency injection in Spring framework.
Inversion of Control is a software engineering principle which delegates the responsibility of controlling the application’s flow to a framework. To make it possible, the frameworks use abstractions and rely on object graphs generated at runtime.
There are several advantages of using the IoC principle:
We can achieve Inversion Of Control either by using a Strategy Design Pattern, Service locator Pattern or Dependency Injection.
Dependency Injection is one of the design patterns which allows us to achieve Inversion Of Control.
In a traditional programming style, we’ll have our classes written as:
public class Person { private Address address; public Person() { this.address = new Address(); } ... }
When using dependency injection, we’ll not create objects on our own and rather inject them. Our Person class would then look something like:
public class Person { private Address address; public Person(Address address) { this.address = address; } ... }
Spring provides an IoC container which is responsible for instantiating, configuring and managing the lifecycle of Spring beans. In Spring, any POJO is referred to as a Spring bean.
The Spring ApplicationContext interface represents its IoC container and we have several implementation classes available. Some of these include ClassPathXmlApplicationContext, FileSystemXmlApplicationContext, and WebApplicationContext.
Let’s instantiate the Spring container using ClassPathXmlApplicationContext:
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Here, the applicationContext.xml is the file that holds the metadata required to assemble beans at runtime.
Spring supports three types of dependency injection:
In a constructor-based injection, Spring will use the matching constructor to resolve and inject the dependency.
We can either configure the beans in applicationContext.xml:
<bean id="address" class="com.programmergirl.domain.Address"/> <bean id="person" class="com.programmergirl.domain.Person"> <constructor-arg ref="address"/> </bean>
Or, we can enable the <component-scan/> in our applicationContext.xml:
<context:component-scan base-package="com.programmergirl.domain" />
On enabling component scan, we can make the Spring configurations using the annotations. Our classes would then look like:
package com.programmergirl.domain; @Component public class Person { private Address address; @Autowired public Person(Address address) { this.address = address; } } package com.programmergirl.domain; @Component public class Address { ... }
Spring, by default, wires the beans by their type. If there are more than one beans of the same type, we can use @Qualifier annotation to reference a bean by its name:
@Component public class Person { private Address address; @Autowired @Qualifier("address1") public void setAddress(Address address) { this.address = address; } }
Assuming we have two Address beans – address1 and address2, our address1 bean will be injected into Person class while dependency resolution.
Setter-based dependency injection is achieved through the setter method on the bean after instantiating it using a no-arg constructor or no-argument static factory.
We can configure it using XML as:
<bean id="address" class="com.programmergirl.domain.Address"/> <bean id="person" class="com.programmergirl.domain.Person"> <property name="address" ref="address"/> </bean>
On the other hand, when using annotations, we’ll have:
@Component public class Person { private Address address; ... @Autowired public void setAddress(Address address) { this.address = address; } }
We can also inject dependencies using fields or properties of a class. To do so, we can simply use the @Autowired annotation over the field:
@Component public class Person { @Autowired private Address address; ... }
considering we’re using annotation based configurations.
As per Spring documentation:
In this quick article, we discussed what is dependency injection. We also discussed the types of dependency injection in Spring framework.