Dependency Injection in Spring

Dependency Injection is the concept of outsourcing the injection of an object’s dependencies to the Spring container.

Dependency injection commonly referred to as DI is one of the most amazing and popular concepts provided by the Spring framework. You can consider it as a design pattern. As the name suggests, it is related to injecting dependencies or we can say helper objects.

The main purpose of dependency injection is to provide loose coupling. For large-scale applications, tightly coupled code can lead to enormous effort during modification in an already created application.

Let’s see what the Dependency Injection concept says and then we will go deep into this concept but with easy and simple words to understand it better:

“The client delegates to call to another object the responsibility of providing its dependencies.”

What is Dependency Injection (DI)?

It’s a pattern that supports the Spring’s Inversion of Control(IOC) concept. IOC is a concept where we outsource the minor or major control of our objects to an external container. So some part of the object’s controls is transferred to an external entity that makes the code loosely coupled.

Dependency Injection is the process of outsourcing the injection of an object’s dependencies into an object to the external container. This way object itself will not be responsible for injecting the dependencies.

In Spring, the dependency injection is handled by the Spring container a.k.a ApplicationContext.

Let’s see how the code without DI concept looks like:

Suppose, we have an object of a class Employee. This Employee class has an instance for Address class. A simple example of Employee has-a Address. In the below example, we have an Employee class, an Address interface, and implementation of Address interface- CurrentAddress.

public class Employee {

    private Address address;

    public Employee() {
        address = new CurrentAddress();
    }
}

The Employee has an Address dependency. We are instantiating Address in the Employee constructor and you can see code is tightly coupled. Suppose, in the future, we need to change the Address instance then we need to change the code in our application. This dependency is hardcoded and it’s a bad approach.

Now look below to find out how code looks like when we are using Spring’s Dependency Injection. Let’s consider the same example:

@Component
public class Employee {

    private Address address;

    @Autowired
    Employee(Address address) {
        this.address = address;
    }

}

See, we are not hard coding the dependency in our class. Instead, the Spring container will inject our dependency. In the above example, we are using constructor injection, which we will cover in detail in the below sections as well as other injection types.

Dependency Injection Types in Spring

There are many ways by which we can implement dependency injection in Spring. Let’s see the overview of all dependency injection types and see what suits best with our project.

Now one thing to note here is that when we are using XML based spring configuration then there are only two dependency injection types:

  1. Constructor Injection
  2. Setter Injection

But with the annotation based spring configuration, we have more options to choose from:

  1. Constructor Injection
  2. Setter Injection
  3. Field Injection
  4. Method Injection

In the below sections, we will dig deeper into these DI types. First, let’s see what can we injecting using the Spring DI feature.

What can we inject by using Dependency Injection in Spring?

Spring has very few limitations if any. It’s a very amazing and popular framework. So it provides flexibility to inject any type of dependency into our objects.

Here is a quick list to understand what type of dependencies can be injected by using spring dependency injection:

  1. Dependency objects
  2. Primitive types
  3. String literals
  4. Collections

So almost everything, right?. Let’s dig deeper into the spring dependency injection and inject dependencies into our object(s) with some practical examples.

First, let’s set up our project so that we can get some hands-on practice in Spring DI.

Spring Project Setup (XML configuration)

We are going to use Eclipse IDE for this example. If you prefer any other IDE, that’s fine too. There will be very minor changes if any in the project setup on different IDEs. So let’s get started:

We will create a Maven project. Go to eclipse IDE and Click on New >> Maven project.

DI maven project creation

Now select “Create a Simple project (skip archetype selection)” and hit Next then you will be presented with the below window. Here, you can add the group and artifact id for your project and hit Finish. Your maven project is created.

DI maven project creation step2

It’s time to do some spring work. Let’s add dependencies that will be needed to implement dependency injection in our project.

We will only need spring-core and spring-context dependencies for now. As we know, the DI feature is part of spring-core dependency and we need spring-context to access implementations of spring container – ApplicationContext.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.9</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.9</version>
</dependency>

To change the java version, however not necessary now, you can add the below properties in your pom.xml of your project:

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

Now we will create an XML file that’ll be used for spring configurations. Let’s create an XML file and name it applicationContext.xml. However, you can choose any name.

We are adding this file in our src/main/java so that it is accessible via the classpath.

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

</beans>

As you can see, it only has schema definitions as of now. This is a simple template of the spring configuration file. These schema definitions are needed to add further configuration.

Now, our building blocks are ready. It’s time to now implement dependency injection so let’s create our employee and other necessary classes, interfaces, etc.

Address.java

package com.app;

public interface Address {
    public String getAddress();
}

Now, provide an implementation of the Address interface:

CurrentAddress.java

package com.app;

@Component
public class CurrentAddress implements Address {

    public String getAddress() {
        return "This is the current address";
    }
}

Notice that we are adding @Component annotation above class CurrentAddress so that it is considered a Spring bean by the spring framework and the spring container will create the bean for this class in the container itself. This is the first step, otherwise, the spring container cannot find this bean, and injecting it into another object is out of context.

Now let’s create our Employee class with Address as a dependency:

Employee.java

package com.app;

import org.springframework.stereotype.Component;

@Component
public class Employee {
    private Address address;
}

Now we have our Employee class with Address in it. Now let’s see how will we use dependency injection by spring to provide the Address dependency to our Employee class.

We have two ways with spring XML configuration to use dependency injection:

  1. Constructor Injection
  2. Setter Injection

We will demonstrate each in the below sections.

Constructor Injection

By using the constructor of a class, we can tell the spring container to inject some dependency into our object. This way of dependency injection is called constructor injection.

Inject Objects

So now let’s change our Employee class to add a constructor that will be used by the spring container to inject the Address dependency into it.

Employee.java

package com.app;

import org.springframework.stereotype.Component;

@Component
public class Employee {

    private Address address;

    public Employee(Address address) {
        this.address = address;
    }

}

You can see, it’s a simple constructor that takes the Address type and assigns it to the Employee’s Address.

Now we need to add configuration in the spring configuration file to make this work.

First, we have to register our Address bean in our spring configuration file. So registering the Address as a spring bean in the spring container can be achieved by the following code:

<bean id="address" class="com.app.CurrentAddress"></bean>

Here, id denotes the name of the bean that’ll be used for uniquely identifying the spring bean and class denotes the class name with the package.

Now, it’s time to register Employee as a spring bean in the configuration file similarly as we defined Address bean

<bean id="employee" class="com.app.Employee"></bean>

Now, we need to tell the spring container that we want dependencies of the Employee class to be injected via constructor injection, and here’s how we do this:

<bean id="employee" class="com.app.Employee">
    <constructor-arg ref="address" />
</bean>

So we use the constructor-arg tag to tell the spring container that we want the constructor to be used for dependency injection and the attribute ref denotes the “id” of the bean that needs to be injected. In easy words, the value in ref should be the same as the value of id for the bean that needs to be injected.

In this case, As the id of the bean Address is address so we put “address” in ref.

So below is our updated applicationContext.xml file.

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">


	<bean id="address" class="com.app.CurrentAddress"></bean>

	<!-- Dependency Injection via constructor injection -->
	<bean id="employee" class="com.app.Employee">
		<constructor-arg ref="address" />
	</bean>

</beans>

Now the final step is to test our project. Let’s write our Main class, where we get these beans from the container and try to print out the address.

Main.java

package com.app;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {

        // Loading the Spring configuration file
        ClassPathXmlApplicationContext context = new 
            ClassPathXmlApplicationContext("applicationContext.xml");

        // Retrieving the bean
        Employee employee = context.getBean("employee", Employee.class);

        // Calling methods on the bean
        System.out.println(employee.getEmployeeAddress());

        // Closing the context
        context.close();

    }
}

Let’s break our code line by line and understand what we are doing.

ClassPathXmlApplicationContext context = 
    new ClassPathXmlApplicationContext("applicationContext.xml");

Here we are using ClassPathXmlApplicationContext to create our spring container and we are passing the name of our spring configuration file so that configurations are loaded into the container. ClassPathXmlApplicationContext is the implementation of ApplicationContext and it represents a Spring container.

Employee employee = context.getBean("employee", Employee.class);

Here, we are retrieving our Employee bean from the spring container using the getBean method. We are passing the id of the bean and type of the bean to the getBean method. This basically will return the instance of Employee class.

This code can also be written as below, both performs the same:

Employee employee = (Employee) context.getBean("employee");

Instead of providing the type of bean in the getBean method, we can explicitly typecast it.

Note: If we neither provide the type of bean and nor typecast it, It will throw compile-time error stating: Type mismatch: Cannot convert from Object to Employee.

System.out.println(employee.getEmployeeAddress());

Here, we are calling the getEmployeeAddress() method of the Employee class to print the address details.

Finally, we are closing the application context.

Let’s see the output of our program:

DI with constrcutor injection

Inject String literal

Now we will look at how we can inject string literals into the objects using constructor injection.

Suppose, in our above CurrentAddress class, we won’t hardcode the address but we will inject the address values via dependency injection. So let’s change our CurrentAddress class.

CurrentAddress.java

package com.app;

import org.springframework.stereotype.Component;

@Component
public class CurrentAddress implements Address {

    
    private String city;
    private String state;
    private String house;

    public CurrentAddress(String city, String house, String state) {

       this.city=city;
       this.state=state;
       this.house=house;
    }

    public String getAddress() {
        return city + ", " + state + ", " + house;
    
    }
}

So we have added three String variables city, state, and house. and we are using constructor injection to inject these values and finally, we have a getAddress method that will concatenate all these variables and return the address as a whole.

Now, let’s see where and how to provide values in these variables.

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">


	<bean id="address" class="com.app.CurrentAddress">
	    <constructor-arg name="city" value="Noida" />
	    <constructor-arg name="state" value="U.P" />
	    <constructor-arg name="house" value="H1234" />
	</bean>

	<!-- Dependency Injection via constructor injection -->
	<bean id="employee" class="com.app.Employee">
		<constructor-arg ref="address" />
	</bean>

</beans>

See, below is the code to inject String literals into the objects using dependency injection using the constructor:

<constructor-arg name="city" value="Noida" />

Same constructor-arg tag, with two attributes name and value. The name denotes the variable name and value holds the value that needs to be injected in that variable. So the city will be set to Noida.

Notice that while injecting objects, we used the ref attribute, and for injecting literals we use to name and value attributes.

Inject Primitives

Let’s change our CurrentAddress class once more and introduce an int variable that we will inject using constructor injection.

So we are adding one more variable int pincode.

CurrentAddress.java

package com.app;

import org.springframework.stereotype.Component;

@Component
public class CurrentAddress implements Address {

    
    private String city;
    private String state;
    private String house;
    private int pincode;

    public CurrentAddress(String city, String house, String state, int pincode) {

       this.city=city;
       this.state=state;
       this.house=house;
       this.pincode=pincode;
    }

    public String getAddress() {
        return city + ", " + state + ", " + house+", "+pincode;
    
    }
}

Similar to the String literal injection. Just need some change in applicationContext.xml for injecting integer or any other primitive value.

We can use the type attribute to specify the type of the value that we want to be injected. if we want int to be injected, we can provide type as int. for double, we can provide type as double, and so on.

<constructor-arg name="pincode" value="1234" type="int"/>

One thing to note here is that providing name and type attributes is not necessary as long as we provide value in the same order as it is passed in the constructor.

Meaning, if we do not provide name and type attribute like below:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">


	<bean id="address" class="com.app.CurrentAddress">
	 <constructor-arg value="Noida" />
	 <constructor-arg  value="U.P" />
	 <constructor-arg  value="H1234" />
	 <constructor-arg  value="1234" />
	 
	</bean>

	<!-- Dependency Injection via constructor injection -->
	<bean id="employee" class="com.app.Employee">
		<constructor-arg ref="address" />
	</bean>

</beans>

Values will be injected in the same order. The first parameter of the constructor will become Noida, second U.P, and so on.

Inject Collections

We can also use constructor injection to inject java collections into the objects. Suppose, we want to inject List into an object. we can do it with dependency injection.

Inject List of String

Let’s modify our Employee class to accept a List.

Let’s add an instance variable to hold the list of assets for the employee:

private List<String> assets;

Now, create a method that will return the String representation of this list:

public String getEmployeeAssets() {
    return assets.toString();
}

We also need to add the parameter List<String> assets in the constructor.

Updated Employee.java

package com.app;

import java.util.List;

import org.springframework.stereotype.Component;

@Component
public class Employee {

    private Address address;
    private List<String> assets;
    
    public Employee(Address address, List<String> assets) {
        this.address = address;
        this.assets=assets;
    }

    public String getEmployeeAddress() {
        return this.address.getAddress();
    }
    
    public String getEmployeeAssets() {
        return assets.toString();
    }
}

To inject a list of values in the object using dependency injection, we can use the <list> tag in our constructor-arg tag in the applicationContext.xml file.

Like this:

<constructor-arg>
    <list>
        <value>Laptop</value>
		<value>Headphones</value>
		<value>ID card</value>
	</list>
</constructor-arg>

This is our updated applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">


	<bean id="address" class="com.app.CurrentAddress">
		<constructor-arg name="city" value="Noida" />
		<constructor-arg name="state" value="U.P" />
		<constructor-arg name="house" value="H1234" />
		<constructor-arg name="pincode" value="1234"
			type="int" />
	</bean>

	<bean id="employee" class="com.app.Employee">
		<constructor-arg ref="address" />
		<constructor-arg>
			<list>
				<value>Laptop</value>
				<value>Headphones</value>
				<value>ID card</value>
			</list>
		</constructor-arg>
	</bean>

</beans>

Let’s test the change by adding below line our Main class:

 System.out.println(employee.getEmployeeAssets());

Main.java

package com.app;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {

        // Loading the Spring configuration file
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // Retrieving the bean
        Employee employee = context.getBean("employee", Employee.class);

        // Calling methods on the bean
        System.out.println(employee.getEmployeeAddress());
        
        System.out.println(employee.getEmployeeAssets());

        // Closing the context
        context.close();

    }
}

Output:

Inject List of Objects

Now, there may be a case, where we want our list to hold objects instead of literals. Let’s see one example of how to inject a list of objects as a dependency into our objects.

Let’s define a List<Address> into our Employee class and a method to get the string representation of this list.

private List<Address> addresses;

public String getEmployeeListOfAddress() {
    return addresses.toString();
}

We also need to override the toString method in CurrentAddress class as we are calling the toString method on the list of address that will internally call toString on CurrentAddress.

@Override
public String toString() {
    return "CurrentAddress [city=" + city + ", state=" + state + ", house=" + house + ", 
        pincode=" + pincode + "]";
}

Employee.java

package com.app;

import java.util.List;

import org.springframework.stereotype.Component;

@Component
public class Employee {

    private Address address;
    private List<String> assets;
    private List<Address> addresses;
    
    public Employee(Address address, List<String> assets, List<Address> addresses) {
        this.address = address;
        this.assets=assets;
        this.addresses=addresses;
    }

    public String getEmployeeAddress() {
        return this.address.getAddress();
    }
    
    public String getEmployeeAssets() {
        return assets.toString();
    }
    
    public String getEmployeeListOfAddress() {
        return addresses.toString();
    }
}

CurrentAddress.java

package com.app;

import org.springframework.stereotype.Component;

@Component
public class CurrentAddress implements Address {

    private String city;
    private String state;
    private String house;
    private int pincode;

    public CurrentAddress(String city, String house, String state, int pincode) {

        this.city = city;
        this.state = state;
        this.house = house;
        this.pincode = pincode;
    }

    public String getAddress() {
        return city + ", " + state + ", " + house + ", " + pincode;

    }

    @Override
    public String toString() {
        return "CurrentAddress [city=" + city + ", state=" + state + ", house=" + house + ", pincode=" + pincode + "]";
    }

}

To inject a list of objects, we can use the following code:

<constructor-arg>
    <list>
        <ref bean="address" />
        <ref bean="address2" />
	</list>
</constructor-arg>

Here, the ref tag is used to denote that we are injecting the object’s list. bean tag denotes the id of the bean that will be inserted in the list. So we need to have two spring beans with id address and address2 respectively in our applicationContext.xml file.

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">


	<bean id="address" class="com.app.CurrentAddress">
		<constructor-arg name="city" value="Noida" />
		<constructor-arg name="state" value="U.P" />
		<constructor-arg name="house" value="H1234" />
		<constructor-arg name="pincode" value="1234"
			type="int" />
	</bean>

	<bean id="address2" class="com.app.CurrentAddress">
		<constructor-arg name="city" value="Kanpur" />
		<constructor-arg name="state" value="U.P" />
		<constructor-arg name="house" value="H9056" />
		<constructor-arg name="pincode" value="2345"
			type="int" />
	</bean>

	<bean id="employee" class="com.app.Employee">
		<constructor-arg ref="address" />
		<constructor-arg>
			<list>
				<value>Laptop</value>
				<value>Headphones</value>
				<value>ID card</value>
			</list>
		</constructor-arg>
		<constructor-arg>
			<list>
				<ref bean="address" />
				<ref bean="address2" />
			</list>
		</constructor-arg>
	</bean>

</beans>

We can test this in our Main class.

Main.java

package com.app;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {

        // Loading the Spring configuration file
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // Retrieving the bean
        Employee employee = context.getBean("employee", Employee.class);

        // Calling methods on the bean
        System.out.println(employee.getEmployeeAddress());
        
        System.out.println(employee.getEmployeeAssets());
        
        System.out.println(employee.getEmployeeListOfAddress());

        // Closing the context
        context.close();

    }
}

Output:

dependency injection output

Inject Map of String

Let’s define a map of String, String in our Employee class. Add the map parameter in the constructor and finally create a method to return the string representation of the map.

private Map<String, String> performanceScore;

public Employee(Address address, List<String> assets, List<Address> addresses, Map<String, String> performanceScore) {
        this.address = address;
        this.assets = assets;
        this.addresses = addresses;
        this.performanceScore = performanceScore;
}

Employee.java

package com.app;

import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Component;

@Component
public class Employee {

    private Address address;
    private List<String> assets;
    private List<Address> addresses;
    private Map<String, String> performanceScore;

    public Employee(Address address, List<String> assets, List<Address> addresses, Map<String, String> performanceScore) {
        this.address = address;
        this.assets = assets;
        this.addresses = addresses;
        this.performanceScore = performanceScore;
    }

    public String getEmployeeAddress() {
        return this.address.getAddress();
    }

    public String getEmployeeAssets() {
        return assets.toString();
    }

    public String getEmployeeListOfAddress() {
        return addresses.toString();
    }

    public String getPerformanceScore() {
        return performanceScore.toString();
    }
}

Now, to define the map in our constructor-arg, we can add the below code in our applicationContext.xml file:

<constructor-arg>
    <map>
       <entry key="Technical" value="Above Expectation"></entry>
	   <entry key="Leadership" value="Average"></entry>
	   <entry key="Communication" value="Met Expectation"></entry>
	</map>
</constructor-arg>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">


	<bean id="address" class="com.app.CurrentAddress">
		<constructor-arg name="city" value="Noida" />
		<constructor-arg name="state" value="U.P" />
		<constructor-arg name="house" value="H1234" />
		<constructor-arg name="pincode" value="1234"
			type="int" />
	</bean>

	<bean id="address2" class="com.app.CurrentAddress">
		<constructor-arg name="city" value="Kanpur" />
		<constructor-arg name="state" value="U.P" />
		<constructor-arg name="house" value="H9056" />
		<constructor-arg name="pincode" value="2345"
			type="int" />
	</bean>

	<bean id="employee" class="com.app.Employee">
		<constructor-arg ref="address" />
		<constructor-arg>
			<list>
				<value>Laptop</value>
				<value>Headphones</value>
				<value>ID card</value>
			</list>
		</constructor-arg>
		<constructor-arg>
			<list>
				<ref bean="address" />
				<ref bean="address2" />
			</list>
		</constructor-arg>
		<constructor-arg>
			<map>
				<entry key="Technical" value="Above Expectation"></entry>
				<entry key="Leadership" value="Average"></entry>
				<entry key="Communication" value="Met Expectation"></entry>
			</map>
		</constructor-arg>
	</bean>

</beans>

Now we can test it by adding the below line in our Main.java file:

System.out.println(employee.getPerformanceScore());

Output:

dependency injection maven project output

Setter Injection

Setter Injection as the name suggests uses a setter for dependency injection. Every setup of code is similar to constructor injection but now we will use setter methods instead of the constructor.

So we will take up the same example to demonstrate it.

Inject Objects

Let’s add one more class to our example to demonstarte use of setter injection to inject dependency objects. We will introduce one more class Department and class Employee will have its dependency. Let’s create our Department class.

Department.java

package com.app;

public class Department {

    private String name;

    public Department(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }
}

Let’s add Department dependency in our existing Employee class. We need to declare the Department and then we will create a setter method that’ll be used by the spring container to inject Department dependency.

private Department department;
    
public void setDepartment(Department department) {
    this.department = department;
}

The final step is to add configuration in applicationContext.xml to use setter injection for Department injection in Employee. Remember, we also need to delare Department bean first while providing name depenedncy.

<bean id="department" class="com.app.Department">
		<constructor-arg value="IT department" />
</bean>

<bean id="employee" class="com.app.Employee">
		<property name="department" ref="department" />
</bean>

You can see we have use <property> tag for setter injection. We use name and ref attributes inside this tag. name attribute refers to the setter method which will be used for injection. Let me explain:

If you have put name=”department” , spring will capitalize this value and append set in this to find setter method name so it will become setDepartment so spring will find setDepartment method and then will inject the object provided in ref attribute.

As we already know ref refers to the bean id of the class.

Inject String literals

Let’s change our CurrentAddress class to hold one more String variable landmark and create a setter method for dependency injection. We will not add landmark in the constructor, as we are not using constructor injection for this specific value. Also, we are adding landmark in our getAddress method and toString method.

private String landmark;

public void setLandmark(String landmark) {
    this.landmark = landmark;
}

public String getAddress() {
   return city + ", " + state + ", " + house + ", " + pincode +", "+landmark;
}

@Override
public String toString() {
    return "CurrentAddress [city=" + city + ", state=" + state + ", house=" + house + ", 
        pincode=" + pincode + ", landmark=" + landmark + "]";
}

Now, let’s add some changes in our spring configuration file to allow dependency injection of String landmark.

<bean id="address" class="com.app.CurrentAddress">
    <property name="landmark" value="STAR HOTEL" />
</bean>

<bean id="address2" class="com.app.CurrentAddress">
    <property name="landmark" value="GREEN PARK" />
</bean>

We have used <property> tag, it is used for setter injection. As we learnt earlier, name attribute helps spring to find the setter method and value provides the string literal to be injected.

Inject Primitives

Injecting primitives and injecting String literrals is exactly same. So we will have to use same <property> tag with name and value attributes.

The code will look something like this:

<property name="employeeId" value="1"/>

Spring Project Setup (annotation based)

Let’s create a new project for dependency injection with annotations. Spring configuration is very verbose and lengthy so using spring annotations always helps.

Let’s create a new project using maven. Go to eclipse IDE and Click on New >> Maven project.

dependency injection using annotations

Now we need to select β€œCreate a Simple project (skip archetype selection)” and press Next and then add the group id and artifact id for your project and pressFinish. Your maven project is created.

dependency injection using annotations step 2

Let’s add some dependencies that are needed to implement dependency injection in our project:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.9</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.9</version>
</dependency>

Now, we will create our spring configuration file named as applicationContext.xml. First, it should have all the schema definitions for spring.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

</beans>

Now, as you know that we will use annotations for creating beans and for dependency injection so we do not need to create beans in this file. Instead, we’ll use annotations to define our bean.

The only thing that we need in our spring configuration file is that we should tell spring the base package where spring can find the beans.

We can provide base package in the applicationContext.xml files like below:

<context:component-scan base-package="com.app" />

So spring will look for all the classes annotated with @Component in the com.app package and all its subpackages and will register that class’s bean automatically.

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<context:component-scan
		base-package="com.app" />

</beans>

Now, we just need our classes to be annotated with @Component and spring will automatically register that bean. So let’s create our classes.

Employee.java

package com.app;

@Component
public class Employee {
    private Address address;
}

Address.java

package com.app;

public interface Address {
   public String getAddress();
}

CurrentAddress.java

package com.app;

@Component
public class CurrentAddress implements Address {

   public String getAddress() {
       return "This is the current address of employee";
   }
   
}

@Autowired annotation

@Autowired annotation reduces so many line of configuration from the spring configuration file. We can use @Autowired annotation for dependency injection in Spring. @Autowired annotation basically wires up the dependencies automatically with the beans.

Spring find out and looks for the class that mathes the type of the bean to be injected and then inject it automatically.

You will learn more clearly with examples explained in below sections.

As Spring automatically wires up the dependencies with the bean it’s called @Autowired or autowiring.

Dependency Injection with @Autowired annotation

Now let’s write some code to understand dependency injection with autowiring more clearly. We will use the classes that we just created on above section of spring configuration with annotation based.

So let’s get started:

Constructor Injection with @Autowired

As the name of this section explains,we are gonna use constructir injection to see how @Autowired annotation can be used on constructor for dependency injection.

So we will start changing our Employee class first. First let’s create our employee class constructor:

    public Employee(Address address) {
        this.address = address;
    }

Now, what we need is just an annotation above this constructor and all other work will be handled by spring automatically.

@Autowired
public Employee(Address address) {
    this.address = address;
}

Now what spring will do, spring will automatically find a bean by type, meaning a bean of Address type and will inject it.

In our case, it’s currentAddess class, so it will inject this in the Employee bean.

Employee.java

package com.app;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Employee {

    private Address address;
    
    @Autowired
    public Employee(Address address) {
        this.address = address;
    }
   
    public String getEmployeeAddress() {
        return this.address.getAddress();
    }
}

Let’s write our Main class to test it out:

Main.java

package com.app;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {

        // Loading the Spring configuration file
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // Retrieving the bean
        Employee employee = context.getBean("employee", Employee.class);

        // Calling methods on the bean
        System.out.println(employee.getEmployeeAddress());

        // Closing the context
        context.close();

    }
}

Output:

Dependency injection with @Autowired

See, so much lesser code gave us exact same results. Thanks to autowiring and @Autowired annotation!

Setter Injection with @Autowired

Instead of constructor, we can also use setters for dependency injection using autowiring.

Everything else remain same, but the Employee class will now have a setter instead of a constructor. Let’s take a look.

Employee.java

package com.app;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Employee {

    private Address address;
    
    /*    @Autowired
    public Employee(Address address) {
        this.address = address;
    }*/
    
    @Autowired
    public void setAddress(Address address) {
        this.address = address;
    }
   
    public String getEmployeeAddress() {
        return this.address.getAddress();
    }
}

The result will remain same. Spring will automatically find Address type bean to inject as a dependency in our Employee class.

Method Injection with @Autowired

Similar to the setter injection, we can use any method with @Autowired annotation and result remains exactly same.

Employee.java

package com.app;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Employee {

    private Address address;

    // Constructor injection
    /*    @Autowired
    public Employee(Address address) {
        this.address = address;
    }*/

    // Setter injection
    /*  @Autowired
    public void setAddress(Address address) {
        this.address = address;
    }*/

    // Method injection
    @Autowired
    public void anyRandomMethod(Address address) {
        this.address = address;
    }

    public String getEmployeeAddress() {
        return this.address.getAddress();
    }
}

Field Injection with @Autowired

My Personal favorite is this one. It does not require constructor, any method, or any setter for dependency injection.

Field injection just requires one line of code. We put @Autowired annotation above the field and it works wonder. It will find the bean by type and inject the dependency automatically.

Let’s take a look:

Employee.java

package com.app;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Employee {

    @Autowired
    private Address address;

    // Constructor injection
    /*    @Autowired
    public Employee(Address address) {
        this.address = address;
    }*/

    // Setter injection
    /*  @Autowired
    public void setAddress(Address address) {
        this.address = address;
    }*/

    // Method injection
    /* @Autowired
    public void anyRandomMethod(Address address) {
        this.address = address;
    }*/

    public String getEmployeeAddress() {
        return this.address.getAddress();
    }
}

How to Inject Values from Properties file?

We have seen several ways and types of dependency injection with spring. But we often use properties file in spring and there is a need to inject those values into our classes. Doing so is extremely easy in Spring framework.

What we need is: First load the properties file into our spring configuration file and then we refer to the property maintained in the properties file.

To load the properties file into our spring comfiguration file, we need to add below code in our applicationContext.xml file.

Here my.properties is our name of properties file.

<context:property-placeholder location="classpath:my.properties"/>

Let’s define our my.properties file:

my.name=ashish

Now if we are using xml based dependency injection, we can add below code inside our bean tag where we want to inject it.

<property name="name" value="${my.name}"/>

${} refers to the properties file’s property.

If we are using annotation, then we can simply declare the value in our class like below:

@Value("${my.name}")
private String name;

Conclusion

We have learned various ways of dependency injection in Spring. Also several type of dependency injection and we also worked on practical examples. The source code for both xml based and annotation based configuration is linked here.

If you have any questions, let me know. Thanks for reading!

Newsletter Updates

Enter your name and email address below to subscribe to our newsletter

Leave a Reply