How To Simplify Dependency Injection with @Autowired
0 CommentsLast Updated on October 21, 2024 by jt
Introduction
Spring provides a way to automatically detect the relationships between various beans. This can be done by declaring all the bean dependencies in Spring configuration file. So, Spring is able to utilize the BeanFactory to know the dependencies across all the used beans.
Autowiring Modes
Spring supports the following autowiring modes:
- no: It’s the default autowiring mode. It means
no
autowiring. - byName: The
byName
mode injects the object dependency according to name of the bean. In such case, property name and bean name should be same. It internally calls setter method. - byType: The
byType
mode injects the object dependency according to type. So it can have different property name and bean name. It internally calls setter method. - constructor: The
constructor
mode injects the dependency by calling the constructor of the class. It calls the constructor having large number of parameters. - autodetect: In this mode, Spring first tries to autowire by
constructor
. If this fails, it tries to autowire by usingbyType
.
1. Autowiring ‘no’:
This is a default autowiring mode. It means no
autowiring.
<bean id="department" class="guru.springframework.autowiringdemo.Department">
<property name="deptName" value="Information Technology" />
</bean>
<bean id="employee" class="guru.springframework.autowiringdemo.Employee"></bean>
2. Autowiring ‘byName’:
This option enables autowire based on bean names. Spring looks up the configuration file for a matching bean name. If found, this bean is injected in the property. However, if no such bean is found, an error is raised.
In this case, the name of the department
bean is same as the employee
bean’s property (Department
), so Spring will be autowired to it via the setter method – setDepartment(Department department)
.
<bean id="department" class="guru.springframework.autowiringdemo.Department">
<property name="deptName" value="Information Technology" />
</bean>
<bean id="employee" class="guru.springframework.autowiringdemo.Employee" autowire="byName"></bean>
3. Autowiring ‘byType’:
This option enables the autowire based on bean type. It searches property’s class type in configuration file. It injects the property, if such bean is found, otherwise an error is raised.
In this case, the data type of the department
bean is same as the data type of the employee
bean’s property (Department
object), therefore Spring will autowire it via the setter method – setDepartment(Department department)
.
<bean id="department" class="guru.springframework.autowiringdemo.Department">
<property name="deptName" value="Information Technology" />
</bean>
<bean id="employee" class="guru.springframework.autowiringdemo.Employee" autowire="byType"></bean>
4. Autowiring ‘constructor’
Autowiring by constructor
is similar to byType
but it applies to constructor arguments. It will look for the class type of constructor arguments, and then do an autowire byType
on all constructor arguments. If exactly one bean of the constructor argument type is not present in the container, a fatal error will be raised.
The data type of department
bean is same as the constructor argument data type in employee
bean’s property (Department
object). Therefore, Spring autowires it using the constructor method – public Employee(Department department)
.
<bean id="department" class="guru.springframework.autowiringdemo.Department">
<property name="deptName" value="Information Technology" />
</bean>
<bean id="employee" class="guru.springframework.autowiringdemo.Employee" autowire="constructor"></bean>
5. Autowiring ‘autodetect’
Autowiring by autodetect
uses two modes i.e. constructor
or byType
modes. First, it will look for valid constructor with arguments. If it is found then the constructor
mode is chosen. If there is no constructor defined in a bean, the autowire byType
mode is chosen.
In following case, since there is a Department
object in the Employee
class, Spring autowires it using byType
via the setter method – setDepartment(Department department)
.
<bean id="department" class="guru.springframework.autowiringdemo.Department">
<property name="deptName" value="Information Technology" />
</bean>
<bean id="employee" class="guru.springframework.autowiringdemo.Employee" autowire="autodetect"></bean>
Note : Autodetect functionality will work with the 2.5 and 2.0 schemas. It will not work from 3.0+.
Example of Autowiring
We’ll create a simple Java Bean, named Department
. Department
will have department name property with getter and setter methods. After that, we will initialize this property value in the Spring bean configuration file.
public class Department {
private String deptName;
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
}
Now let’s create our Employee
class. In which we will inject Department
bean through Spring autowiring.
public class Employee {
private int eid;
private String ename;
private Department department;
public int getEid() {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public void showEployeeDetails(){
System.out.println("Employee Id : " + eid);
System.out.println("Employee Name : " + ename);
System.out.println("Department : " + department.getDeptName());
}
}
Now, looking at Spring bean configuration file, it is the main part of any Spring application. So let’s see how our Spring bean configuration file looks.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
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="department" class="guru.springframework.autowiringdemo.Department">
<property name="deptName" value="Information Technology" />
</bean>
<bean id="emp" class="guru.springframework.autowiringdemo.Employee" autowire="byName"></bean>
</beans>
Now, our Spring application is ready with all types of Spring autowiring. So let’s write a simple test program to see if it works as expected.
@SpringBootApplication
public class AutowiringdemoApplication {
public static void main(String[] args) {
SpringApplication.run(AutowiringdemoApplication.class, args);
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Employee emp = context.getBean("employee", Employee.class);
emp.setEid(101);
emp.setEname("Spring Framework Guru");
emp.showEployeeDetails();
}
}
In the above program, we are just creating the Spring application context and using it to get different beans and printing the employee details.
After we run the above program, we get the following output:
Employee Id : 101
Employee Name : Spring Framework Guru
Department : Information Technology
Process finished with exit code 0
@Autowired Annotation
In Spring, you can use @Autowired
annotation to auto wire bean on the setter method, constructor or a field. Moreover, it can autowire property in a particular bean. We must first enable the annotation using below configuration in configuration file.
If you are using Java based configuration, you can enable annotation-driven injection by using below spring configuration:
@Configuration
@ComponentScan("guru.springframework.autowiringdemo")
public class AppConfig {}
As an alternative, we can use below XML based configuration in Spring:
<context:annotation-config />
We have enabled annotation injection. After that, it can be used on modes like properties, setters, and constructors. Let’s discuss them one by one.
@Autowired on Properties
In the below example, when the annotation is directly used on properties, Spring looks for and injects Department
when Employee
is created. This is how it eliminates the need for getters and setters.
import org.springframework.stereotype.Component;
@Component
public class Department {
private String deptName;
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
}
import org.springframework.beans.factory.annotation.Autowired;
public class Employee {
private int eid;
private String ename;
@Autowired
private Department department;
public int getEid() {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public void showEployeeDetails(){
System.out.println("Employee Id : " + eid);
System.out.println("Employee Name : " + ename);
department.setDeptName("Information Technology");
System.out.println("Department : " + department.getDeptName());
}
}
@Autowired on Setters
In the below example, when the annotation is used on the setter method, the setter method is called with the instance of Department
when Employee
is created.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Employee {
private int eid;
private String ename;
private Department department;
public int getEid() {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Department getDepartment() {
return department;
}
@Autowired
public void setDepartment(Department department) {
this.department = department;
}
public void showEployeeDetails(){
System.out.println("Employee Id : " + eid);
System.out.println("Employee Name : " + ename);
department.setDeptName("Information Technology");
System.out.println("Department : " + department.getDeptName());
}
}
@Autowired on Constructors
In the below example, the annotation is used on a constructor, an instance of Department
is injected as an argument to the constructor when Employee
is created.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Employee {
private int eid;
private String ename;
private Department department;
@Autowired
public EmployeeBean(DepartmentBean deptBean) {
System.out.println("*** Autowiring by using @Autowire annotation on constructor ***");
this.deptBean = deptBean;
}
public int getEid() {
return eid;
}
public void setEid(int eid) {
this.eid = eid;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public void showEployeeDetails(){
System.out.println("Employee Id : " + eid);
System.out.println("Employee Name : " + ename);
department.setDeptName("Information Technology");
System.out.println("Department : " + department.getDeptName());
}
}
Understanding Autowiring: Setter vs. Constructor Injection
Autowiring is a powerful feature that simplifies dependency management in frameworks like Spring. But how exactly does it utilize setter and constructor injection internally?
Setter Injection
- Mechanism: This approach involves injecting dependencies through public setter methods. When the framework initializes a bean, it calls these setter methods to provide the required dependencies.
- Use Case: It’s particularly useful when you have a large number of optional dependencies. It allows for more flexibility, as dependencies can be changed or updated after object creation.
Constructor Injection
- Mechanism: With this method, dependencies are injected through the class constructor. The framework resolves all the dependencies by passing them as arguments when creating a new instance of the class.
- Use Case: This is preferred when you have mandatory dependencies. It ensures that all necessary components are available to the object at the time of creation, promoting immutability and easier testing.
Choosing Between the Two
- Immutability: Constructor injection promotes immutability, as fields are set once at construction time and aren’t changeable afterward.
- Optional Dependencies: Setter injection is better suited when optional dependencies are involved.
By leveraging autowiring, the framework automatically selects between these two types of injection based on the configuration and requirement, effectively reducing boilerplate code and enhancing modularity.
Writing a Test Program
So let’s write a simple test program for @Autowired
on property to see if it works as expected.
@SpringBootApplication
public class AutowiringdemoApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(AutowiringdemoApplication.class, args);
Employee emp = context.getBean(Employee.class);
emp.setEid(104);
emp.setEname("Spring Framework Guru");
emp.showEployeeDetails();
}
}
After we run the above program, we get the following output:
Employee Id : 104
Employee Name : Spring Framework Guru
Department : Information Technology
Process finished with exit code 0
Autowire Conflict Resolution
By default, Spring resolves @Autowired
entries byType
. If more than one beans of the same type are available in the container, the framework will throw NoUniqueBeanDefinitionException
exception indicating that more than one bean is available for autowiring. Please click here to know more on how to fix NoUniqueBeanDefinitionException
exceptions.
Summary
In this post, we’ve seen a few modes of the autowiring object using Spring ApplicationContext and Spring configuration file. We have looked at examples using different modes which are:
no
byName
byType
constructor
autodetect
We also saw a simple examples of autowiring using @Autowired
annotation using different modes which are:
property
setter
constructor
You can download the complete source code of this post from GitHub.
What Are the Advantages of Using Autowiring in Spring?
Autowiring in Spring brings several compelling benefits that streamline the development process and enhance code maintainability.
1. Reduces Boilerplate Code
One of the standout advantages of autowiring is its ability to minimize boilerplate code. Developers aren’t bogged down with manually writing code for dependency injection, which simplifies development and makes the code cleaner.
2. Enhances Readability and Maintainability
By automating the injection of dependencies, autowiring makes the codebase more readable. This automatic configuration reduces clutter, making it easier to understand and maintain over time.
3. Facilitates Quicker Development
With autowiring, developers can focus on building core application features rather than managing dependencies. This leads to faster development times, as setting up components becomes a more seamless process.
4. Boosts Flexibility and Scalability
Autowiring provides flexibility to swap components without modifying much of the existing code. This adaptability is essential for scaling and evolving applications as business needs change.
5. Encourages Loose Coupling
By employing autowiring, applications inherently support loose coupling. Objects are less dependent on each other, improving the architecture’s flexibility and making it easier to manage changes in the application structure.
Incorporating autowiring into your Spring projects can lead to cleaner, more efficient code, ultimately resulting in a more agile and robust application development process.