Spring @Autowired 注釋用於自動依賴注入。 Spring 框架 建立在 依賴注入 上,我們通過 Spring bean 配置文件注入類的依賴。
Spring @Autowired 注釋
通常我們在 Spring bean 配置文件中提供 bean 配置詳情,同時還使用
ref
屬性指定將被注入到其他 bean 中的 beans。但 Spring 框架還提供了自動連線功能,我們不需要明確提供 bean 注入詳情。有多種方式可以自動連線 Spring bean。
- 按名稱自動連線 – 對於這種類型的自動連線,setter 方法用於依賴注入。同時,在我們將依賴注入的類中和 Spring bean 配置文件中的變量名稱應該相同。
- autowire byType – 對於這種自動裝配,使用類型進行裝配。因此,在Spring bean配置文件中應該只配置一個針對此類型的bean。
- autowire by constructor – 這幾乎與autowire byType相似,唯一的區別是使用構造函數來注入依賴關係。
- autowire by autodetect – 如果您使用的是Spring 3.0或更舊的版本,這是可用的autowire選項之一。此選項用於由Spring容器確定的構造函數或byType的自動裝配。由於我們已經有很多選擇,此選項已被棄用。我將在本教程中不涉及此選項。
-
@Autowired
註解 – 我們可以使用Spring @Autowired 註解進行spring bean自動裝配。@Autowired 註解可應用於按類型進行自動裝配的變量和方法。我們還可以在構造函數上使用 @Autowired 註解進行基於構造函數的spring自動裝配。為了使 @Autowired 註解工作,我們還需要在spring bean配置文件中啟用基於註解的配置。這可以通過 context:annotation-config 元素或定義一個org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
類型的bean 來完成。 @Qualifier
注解 – 此注解用于避免在 bean 映射中发生冲突,我们需要提供将用于自动装配的 bean 名称。通过这种方式,我们可以避免为相同类型定义多个 bean 导致的问题。该注解通常与 @Autowired 注解一起使用。对于具有多个参数的构造函数,我们可以在方法中使用此注解并提供参数名称。
默认情况下,Spring Bean 的自动装配是关闭的。Spring Bean 的自动装配默认值为“default”,这意味着不执行自动装配。autowire 值为“no”也具有相同的行为。为了展示 Spring Bean 的自动装配的用法,让我们创建一个简单的 Spring Maven 项目。我们的最终项目将如下图所示。 让我们逐一查看每个自动装配选项。为此,我们将创建一个模型 bean 和一个服务类,在其中我们将注入模型 bean。
Spring @Autowired 注解 – Maven 依赖
对于 Spring 的自动装配,我们不需要添加任何额外的依赖项。我们的 pom.xml 文件包含 Spring 框架核心依赖项,如下所示。
<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>
Spring @Autowired 註釋 – 模型 Bean
讓我們創建一個簡單的Java Bean,名為 Employee。這個 Bean 將具有一個單一的屬性,並帶有 getter 和 setter 方法。我們將在 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;
}
}
Spring @Autowired 註釋 – 服務類
讓我們創建我們的服務類,我們將通過 Spring 自動裝配注入 Employee Bean。
package com.journaldev.spring.autowiring.service;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeService {
private Employee employee;
// 構造函數用於按構造函數自動裝配
public EmployeeService(Employee emp) {
System.out.println("Autowiring by constructor used");
this.employee = emp;
}
// 默認構造函數,以避免 BeanInstantiationException 自動裝配
// 按名稱或按類型
public EmployeeService() {
System.out.println("Default Constructor used");
}
// 用於按名稱和按類型自動裝配
public void setEmployee(Employee emp) {
this.employee = emp;
}
public Employee getEmployee() {
return this.employee;
}
}
我們將使用相同的服務類來執行Spring按名字、按類型和按構造函數的自動裝配。設置器方法將用於Spring按名字和按類型的自動裝配,而構造函數注入將由構造函數的autowire屬性使用。當我們使用Spring按名字或按類型進行自動裝配時,將使用默認構造函數。這就是為什麼我們為EmployeeService bean明確定義了默認構造函數。
Spring @Autowired 註解 – 按類型自動裝配示例
讓我們為Spring注解創建一個獨立的類,以進行按類型的自動裝配。
package com.journaldev.spring.autowiring.service;
import org.springframework.beans.factory.annotation.Autowired;
import com.journaldev.spring.autowiring.model.Employee;
public class EmployeeAutowiredByTypeService {
//在變量/設置器上的Autowired註解等同於autowire="byType"
@Autowired
private Employee employee;
@Autowired
public void setEmployee(Employee emp){
this.employee=emp;
}
public Employee getEmployee(){
return this.employee;
}
}
請注意,我已經用Spring @Autowired註解註釋了Employee變量及其設置器方法,但這兩者中只需要一個就足以進行Spring bean的自動裝配。
Spring@Autowired註釋和@Qualifier通過構造函數自動裝配的示例
讓我們創建另一個服務類,在這裡我們將使用@Autowired註釋進行基於構造函數的注入。我們還將看到@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註釋等同於autowire="constructor"
@Autowired(required=false)
public EmployeeAutowiredByConstructorService(@Qualifier("employee") Employee emp){
this.employee=emp;
}
public Employee getEmployee() {
return this.employee;
}
}
當Spring框架初始化這個bean時,將使用名稱為”employee”的bean進行自動裝配。Spring @Autowired註釋接受一個參數”required”,默認值為TRUE的布爾值。我們可以將其定義為”false”,這樣如果沒有適合的bean用於自動裝配,Spring框架就不會拋出任何異常。
Spring @Autowired 註解 – Bean 配置文件
Spring bean 配置文件是任何 Spring 應用程序的主要部分,讓我們看看我們的 Spring bean 配置文件的外觀,然後我們將深入研究它的每個部分。
<?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>
關於 Spring bean 配置文件的重要點包括:
- beans 元素
default-autowire
用於定義默認的自動裝配方法。在這裡,我將默認的自動裝配方法定義為 byName。 - beans 元素
default-autowire-candidates
用於提供可用於自動裝配的 bean 名稱的模式。為了簡單起見,我允許所有 bean 定義都符合自動裝配的條件,但是如果我們可以為自動裝配定義一些模式。例如,如果我們只想要將 DAO bean 定義用於自動裝配,我們可以將其指定為default-autowire-candidates="*DAO"
。 autowire-candidate="false"
用於 bean 定義中,使其不符合自動裝配的條件。當我們對於單一類型有多個 bean 定義,並且我們希望其中一些不被自動裝配時,這很有用。例如,在上述 Spring bean 配置中,“employee1” bean 將不會被用於自動裝配。- autowire 屬性 byName、byType 和 constructor 是自明的,沒有太多需要解釋的。
context:annotation-config
用於啟用基於註釋的配置支援。請注意,employeeAutowiredByTypeService 和 employeeAutowiredByConstructorService 這兩個 bean 沒有 autowire 屬性。
Spring @Autowired註釋 – 測試程式
現在我們的 Spring 應用程式已經準備好了各種類型的 Spring 自動連線,讓我們撰寫一個簡單的測試程式來檢查它是否按預期運作。
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());
//列印 hashcode 以確認所有物件都是不同類型的
System.out.println(serviceByName.hashCode()+"::"+serviceByType.hashCode()+"::"+serviceByConstructor.hashCode());
//測試 @Autowired 註釋
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();
}
}
這個程式很簡單,我們只是創建了 Spring 應用程式上下文並使用它來獲取不同的 bean,然後印出員工的名字。當我們運行上述應用程式時,我們會得到以下輸出。
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
正如您所看到的,對於按名稱和按類型自動裝配,默認使用無參數構造函數來初始化bean。對於按構造函數自動裝配,則使用基於參數的構造函數。從所有變量的哈希碼中,我們確認所有的Spring beans都是不同的對象,而不是引用同一個對象。由於我們從自動裝配的合格bean列表中刪除了“employee1”,因此在bean映射中沒有混淆。如果從“employee1”的定義中刪除`autowire-candidate=”false”`,則在執行上述主方法時將獲得下面的錯誤消息。
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
這就是有關Spring @Autowired 註解和Spring自動裝配功能的所有內容,請從下面的鏈接下載示例項目並進行分析以了解更多。
Source:
https://www.digitalocean.com/community/tutorials/spring-autowired-annotation