Spring的@Autowired注解用于自动依赖注入。Spring框架建立在依赖注入的基础上,我们通过Spring的bean配置文件来注入类的依赖关系。
Spring @Autowired注解
通常,我们在Spring的bean配置文件中提供bean配置细节,并使用
ref
属性指定将注入其他bean的bean。但是Spring框架也提供了自动装配的功能,我们不需要显式地提供bean注入详情。有多种方式可以自动装配Spring的bean。
- 按名称自动装配 – 对于这种类型的自动装配,使用setter方法进行依赖注入。在类中,变量名和Spring的bean配置文件中将注入依赖关系的地方应该相同。
- autowire byType – 对于这种类型的自动装配,使用类类型。因此,在Spring Bean配置文件中应该只配置一个与此类型相对应的bean。
-
autowire by constructor – 这几乎与autowire byType相似,唯一的区别在于使用构造函数来注入依赖项。
-
autowire by autodetect – 如果您使用的是Spring 3.0或更早版本,则这是其中一个可用的自动装配选项。此选项用于根据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项目。我们的最终项目将如下图所示。让我们逐个查看每个自动装配选项。为此,我们将创建一个Model bean和一个service类,在其中我们将注入Model 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的按名称、按类型和按构造函数自动装配。Setter方法将用于Spring的按名称和按类型自动装配,而构造函数基于注入将使用构造函数自动装配属性。当我们使用Spring的按名称或按类型自动装配时,默认构造函数会被使用。这就是为什么我们为EmployeeService bean显式定义了默认构造函数。
Spring@Autowired注解-按类型自动装配示例
让我们创建一个单独的类,其中包含Spring@Autowired注解,用于按类型自动装配。
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变量及其setter方法进行了注解,但是只有其中之一对于spring bean自动装配是足够的。
Spring注解和@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;
}
}
当此bean由Spring框架初始化时,名称为“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` beans 没有 `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());
// 打印哈希码以确认所有对象的类型都不同
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 Bean 都是不同的对象,而不是引用相同的对象。由于我们从自动装配的合格 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