Annotation @Autowired trong Spring được sử dụng để tiêm phụ thuộc tự động (dependency injection). Framework Spring được xây dựng dựa trên nguyên tắc dependency injection và chúng ta khai báo các phụ thuộc của class thông qua file cấu hình Spring bean.

Annotation @Autowired trong Spring
Trong Spring Framework, việc cấu hình các bean và chỉ định các bean được tiêm vào các bean khác thường được thực hiện thủ công trong tệp cấu hình XML bằng thuộc tính ref. Tuy nhiên, Spring cũng cung cấp tính năng autowiring cho phép chúng ta không cần phải cung cấp chi tiết tiêm bean một cách tường minh. Có nhiều cách khác nhau để autowiremột Spring bean:
- autowire byName – Với loại autowiring này, Spring sử dụng phương thức setter để tiêm phụ thuộc. Điều kiện là tên biến trong lớp nơi chúng ta muốn tiêm phụ thuộc và tên bean trong tệp cấu hình Spring phải giống nhau.
- autowire byType – Đối với loại autowiring này, Spring dựa vào kiểu lớp (class type). Do đó, chỉ nên có một bean được cấu hình với kiểu này trong tệp cấu hình Spring để tránh xung đột.
- autowire by constructor – Loại này khá giống với
autowire byType, điểm khác biệt duy nhất là constructor được sử dụng để tiêm phụ thuộc. - autowire by autodetect – Nếu bạn đang sử dụng Spring 3.0 hoặc các phiên bản cũ hơn, đây là một trong những tùy chọn autowire có sẵn. Tùy chọn này được sử dụng để tự động kết nối theo
constructorhoặcbyType, tùy thuộc vào việc Spring container xác định. Vì chúng ta đã có rất nhiều tùy chọn khác nên tùy chọn này đã bị deprecated (không còn được khuyến khích sử dụng). Vì vậy, tôi sẽ không đề cập đến tùy chọn này trong hướng dẫn này. - @Autowired annotation – Chúng ta có thể sử dụng annotation @Autowired để tự động kết nối Spring bean.
@Autowiredannotation có thể được áp dụng trên các biến và phương thức để autowiring theo kiểubyType. Chúng ta cũng có thể sử dụng@Autowiredannotation trên constructor để autowire dựa trên constructor của Spring. Để@Autowiredannotation hoạt động, chúng ta cũng cần bật cấu hình dựa trên chú thích trong tệp cấu hình Spring bean. Điều này có thể được thực hiện bằng cách sử dụng phần tử<context:annotation-config>hoặc bằng cách định nghĩa một bean có kiểuorg.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor - @Qualifier annotation – Annotation này được sử dụng để tránh xung đột trong việc ánh xạ bean. Chúng ta cần cung cấp tên bean sẽ được sử dụng để autowiring. Bằng cách này, chúng ta có thể tránh các vấn đề khi nhiều bean được định nghĩa cho cùng một kiểu. Annotation này thường hoạt động cùng với annotation
@Autowired. Đối với các constructor có nhiều đối số, chúng ta có thể sử dụng chú thích này với tên đối số trong phương thức.
Mặc định, autowiring trong Spring bean đã bị tắt. Giá trị mặc định của autowire trong Spring bean là "default", có nghĩa là không có autowiring nào được thực hiện. Giá trị autowire "no" cũng có hành vi tương tự. Để minh họa việc sử dụng Spring Bean autowiring, hãy tạo một dự án Spring Maven đơn giản. Dự án cuối cùng của chúng ta sẽ trông như hình ảnh bên dưới.

Bây giờ chúng ta sẽ đi sâu vào từng tùy chọn autowire một. Để làm được điều đó, chúng ta sẽ tạo một Model bean và một service class để tiêm model bean vào đó.
@Autowired trong Spring – Maven dependencies
Để sử dụng autowiring trong Spring, chúng ta không cần thêm bất kỳ dependency nào đặc biệt. Tệp pom.xml của chúng ta chỉ cần có các dependency cốt lõi của Spring Framework và trông như ví dụ dưới đây:
<project xmlns="<https://maven.apache.org/POM/4.0.0>" xmlns:xsi="<https://www.w3.org/2001/XMLSchema-instance>"
xsi:schemaLocation="<https://maven.apache.org/POM/4.0.0> <https://maven.apache.org/xsd/maven-4.0.0.xsd>">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>SpringBeanAutowiring</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>4.0.2.RELEASE</spring-framework.version>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
</properties>
<dependencies>
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
Annotation @Autowired trong Spring – Model Bean
Để bắt đầu, chúng ta sẽ tạo một Java Bean đơn giản có tên là Employee. Bean này sẽ có một thuộc tính duy nhất, đi kèm với các phương thức getter và setter. Chúng ta sẽ khởi tạo giá trị cho thuộc tính này trong tệp cấu hình Spring bean.
package com.journaldev.spring.autowiring.model;
public class Employee {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Annotation @Autowired trong Spring – Service class
Hãy tạo lớp dịch vụ của chúng ta, nơi chúng ta sẽ tiêm Employee bean thông qua tính năng autowiring của Spring.
package com.journaldev.spring.autowiring.service;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeService {
private Employee employee;
// constructor is used for autowire by constructor
public EmployeeService(Employee emp) {
System.out.println("Autowiring by constructor used");
this.employee = emp;
}
// default constructor to avoid BeanInstantiationException for autowire
// byName or byType
public EmployeeService() {
System.out.println("Default Constructor used");
}
// used for autowire byName and byType
public void setEmployee(Employee emp) {
this.employee = emp;
}
public Employee getEmployee() {
return this.employee;
}
}
Chúng ta sẽ sử dụng cùng một lớp dịch vụ để thực hiện autowiring của Spring theo kiểu byName, byType và by constructor. Phương thức setter sẽ được dùng cho autowiring byName và byType, trong khi đó, tiêm dựa trên constructor sẽ được sử dụng bởi thuộc tính autowire by constructor. Khi chúng ta dùng autowire của Spring theo kiểu byName hoặc byType, constructor mặc định sẽ được sử dụng. Đó là lý do tại sao chúng ta đã định nghĩa rõ ràng constructor mặc định cho EmployeeService bean.
Annotation @Autowired trong Spring – Ví dụ Autowiring byType
Hãy tạo một lớp riêng biệt với chú thích Spring @Autowired để thực hiện autowiring byType.
package com.journaldev.spring.autowiring.service;
import org.springframework.beans.factory.annotation.Autowired;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeAutowiredByTypeService {
//Autowired annotation on variable/setters is equivalent to autowire="byType"
@Autowired
private Employee employee;
@Autowired
public void setEmployee(Employee emp){
this.employee=emp;
}
public Employee getEmployee(){
return this.employee;
}
}
Lưu ý rằng tôi đã chú thích cả biến Employee và phương thức setter của nó bằng chú thích @Autowired của Spring; tuy nhiên, chỉ một trong số đó là đủ để thực hiện autowiring bean của Spring.
Annotation @Autowired của Spring và @Qualifier – Ví dụ Autowiring Bean bằng Constructor
Hãy tạo một service class khác, nơi chúng ta sẽ sử dụng chú thích @Autowired cho tiêm dựa trên constructor. Chúng ta cũng sẽ xem cách sử dụng chú thích @Qualifier.
package com.journaldev.spring.autowiring.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeAutowiredByConstructorService {
private Employee employee;
//Autowired annotation on Constructor is equivalent to autowire="constructor"
@Autowired(required=false)
public EmployeeAutowiredByConstructorService(@Qualifier("employee") Employee emp){
this.employee=emp;
}
public Employee getEmployee() {
return this.employee;
}
}
Khi bean này được khởi tạo bởi Spring Framework, bean có tên là “employee” sẽ được sử dụng cho việc autowiring. Chú thích @Autowired của Spring chấp nhận một đối số “required” là một giá trị boolean với giá trị mặc định là TRUE. Chúng ta có thể đặt nó thành “false” để Spring Framework không ném ra bất kỳ ngoại lệ nào nếu không tìm thấy bean phù hợp cho việc autowiring.
@Autowired của Spring – Tệp Cấu hình Bean
Tệp cấu hình bean của Spring là phần chính của bất kỳ ứng dụng Spring nào. Hãy xem tệp cấu hình bean của chúng ta sẽ trông như thế nào, sau đó chúng ta sẽ đi sâu vào từng phần của nó.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="<https://www.springframework.org/schema/beans>"
xmlns:xsi="<https://www.w3.org/2001/XMLSchema-instance>"
xmlns:context="<https://www.springframework.org/schema/context>"
xsi:schemaLocation="<https://www.springframework.org/schema/beans> <https://www.springframework.org/schema/beans/spring-beans.xsd>
<https://www.springframework.org/schema/context> <https://www.springframework.org/schema/context/spring-context-4.0.xsd>"
default-autowire="byName" default-autowire-candidates="*" >
<bean name="employee" class="com.journaldev.spring.autowiring.model.Employee">
<property name="name" value="Pankaj"></property>
</bean>
<bean name="employee1" class="com.journaldev.spring.autowiring.model.Employee" autowire-candidate="false">
<property name="name" value="Dummy Name"></property>
</bean>
<!-- autowiring byName, bean name should be same as the property name -->
<bean name="employeeServiceByName" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="byName" />
<!-- autowiring byType, there should be only one bean definition for the mapping -->
<bean name="employeeServiceByType" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="byType" />
<!-- autowiring by constructor -->
<bean name="employeeServiceConstructor" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="constructor" />
<!-- Enable Annotation based configuration -->
<context:annotation-config />
<!-- using @Autowiring annotation in below beans, byType and constructor -->
<bean name="employeeAutowiredByTypeService" class="com.journaldev.spring.autowiring.service.EmployeeAutowiredByTypeService" />
<bean name="employeeAutowiredByConstructorService" class="com.journaldev.spring.autowiring.service.EmployeeAutowiredByConstructorService" />
</beans>
Các điểm quan trọng về tệp cấu hình Spring Bean:
- Thuộc tính
default-autowirecủa phần tử<beans>: Thuộc tính này được dùng để định nghĩa phương thức autowiring mặc định. Ở đây, tôi đang đặt phương thức autowiring mặc định làbyName. - Thuộc tính
default-autowire-candidatescủa phần tử<beans>: Thuộc tính này được dùng để cung cấp mẫu (pattern) cho các tên bean có thể được sử dụng để autowiring. Để đơn giản, tôi đang cho phép tất cả các định nghĩa bean đều đủ điều kiện để autowiring. Tuy nhiên, chúng ta có thể định nghĩa một mẫu cụ thể cho autowiring. Ví dụ, nếu chúng ta chỉ muốn các định nghĩa bean DAO được autowiring, chúng ta có thể chỉ định làdefault-autowire-candidates="*DAO". - Thuộc tính
autowire-candidate="false": Thuộc tính này được sử dụng trong một định nghĩa bean để làm cho nó không đủ điều kiện cho autowiring. Nó hữu ích khi chúng ta có nhiều định nghĩa bean cho một kiểu duy nhất và chúng ta muốn một số trong số chúng không được autowire. Ví dụ, trong các cấu hình Spring bean ở trên, bean “employee1” sẽ không được sử dụng cho autowiring. - Thuộc tính
autowirevới các giá trịbyName,byTypevàconstructor: Các thuộc tính này tự giải thích, không có gì nhiều để diễn giải thêm. - Phần tử
<context:annotation-config>: Phần tử này được sử dụng để kích hoạt hỗ trợ cấu hình dựa trên chú thích (annotation based configuration). Lưu ý rằng các beanemployeeAutowiredByTypeServicevàemployeeAutowiredByConstructorServicekhông có thuộc tínhautowire.
@Autowired của Spring – Chương trình test
Bây giờ ứng dụng Spring của chúng ta đã sẵn sàng với tất cả các kiểu autowiring của Spring, hãy viết một chương trình kiểm tra đơn giản để xem liệu nó có hoạt động như mong đợi hay không.
package com.journaldev.spring.autowiring.main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.journaldev.spring.autowiring.service.EmployeeAutowiredByConstructorService;
import com.journaldev.spring.autowiring.service.EmployeeAutowiredByTypeService;
import com.journaldev.spring.autowiring.service.EmployeeService;
public class SpringMain {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
EmployeeService serviceByName = ctx.getBean("employeeServiceByName", EmployeeService.class);
System.out.println("Autowiring byName. Employee Name="+serviceByName.getEmployee().getName());
EmployeeService serviceByType = ctx.getBean("employeeServiceByType", EmployeeService.class);
System.out.println("Autowiring byType. Employee Name="+serviceByType.getEmployee().getName());
EmployeeService serviceByConstructor = ctx.getBean("employeeServiceConstructor", EmployeeService.class);
System.out.println("Autowiring by Constructor. Employee Name="+serviceByConstructor.getEmployee().getName());
//printing hashcode to confirm all the objects are of different type
System.out.println(serviceByName.hashCode()+"::"+serviceByType.hashCode()+"::"+serviceByConstructor.hashCode());
//Testing @Autowired annotations
EmployeeAutowiredByTypeService autowiredByTypeService = ctx.getBean("employeeAutowiredByTypeService",EmployeeAutowiredByTypeService.class);
System.out.println("@Autowired byType. Employee Name="+autowiredByTypeService.getEmployee().getName());
EmployeeAutowiredByConstructorService autowiredByConstructorService = ctx.getBean("employeeAutowiredByConstructorService",EmployeeAutowiredByConstructorService.class);
System.out.println("@Autowired by Constructor. Employee Name="+autowiredByConstructorService.getEmployee().getName());
ctx.close();
}
}
Chương trình này khá đơn giản, chúng ta chỉ tạo Spring application context và sử dụng nó để lấy các bean khác nhau rồi in ra tên nhân viên. Khi chạy ứng dụng trên, chúng ta sẽ nhận được kết quả như sau:
Mar 31, 2014 10:41:58 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3fa99295: startup date [Mon Mar 31 22:41:58 PDT 2014]; root of context hierarchy
Mar 31, 2014 10:41:58 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
Default Constructor used
Default Constructor used
Autowiring by constructor used
Autowiring byName. Employee Name=Pankaj
Autowiring byType. Employee Name=Pankaj
Autowiring by Constructor. Employee Name=Pankaj
21594592::15571401::1863015320
@Autowired byType. Employee Name=Pankaj
@Autowired by Constructor. Employee Name=Pankaj
Mar 31, 2014 10:41:58 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@3fa99295: startup date [Mon Mar 31 22:41:58 PDT 2014]; root of context hierarchy
Như bạn có thể thấy, đối với autowire byName và byType, constructor mặc định không có đối số được sử dụng để khởi tạo bean. Đối với autowire by constructor, constructor có tham số được sử dụng. Từ mã băm (hashcode) của tất cả các biến, chúng ta đã xác nhận rằng tất cả các Spring bean là các đối tượng khác nhau và không tham chiếu đến cùng một đối tượng.
Vì chúng ta đã loại bỏ “employee1” khỏi danh sách các bean đủ điều kiện để autowiring, nên không có sự nhầm lẫn nào trong việc ánh xạ bean. Nếu chúng ta bỏ thuộc tính autowire-candidate="false" khỏi định nghĩa “employee1”, chúng ta sẽ nhận được thông báo lỗi dưới đây khi thực thi phương thức main ở trên.
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'employeeServiceByType' defined in class path resource [spring.xml]: Unsatisfied dependency expressed through bean property 'employee': : No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1278)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1170)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:700)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.journaldev.spring.autowiring.main.SpringMain.main(SpringMain.java:12)
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.journaldev.spring.autowiring.model.Employee] is defined: expected single matching bean but found 2: employee,employee1
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:967)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1263)
... 13 more
Đó là tất cả những gì về annotation @Autowired trong Spring. Hy vọng bài viết đã giúp bạn hiểu rõ cách hoạt động và cách sử dụng @Autowired trong dự án của mình. Nếu có thắc mắc hoặc cần hỗ trợ thêm, đừng ngần ngại để lại bình luận nhé!