Spring @Autowired注释用于自动依赖注入。Spring框架是基于依赖注入构建的,我们通过spring bean配置文件注入类依赖项。
目录[ 隐藏 ]
通常我们在spring bean配置文件中提供bean配置细节,并且我们还使用ref
attribute 指定将在其他bean中注入的bean 。但Spring框架也提供了自动装配功能,我们不需要明确提供bean注入细节。
我们可以通过不同的方式自动装配一个spring bean。
@Autowired
注释 - 我们可以使用Spring @Autowired注释进行spring bean自动装配。@Autowired注释可以应用于自动装配byType的变量和方法。我们还可以在构造函数上使用@Autowired注释来构造基于Spring的自动装配。 要使@Autowired注释起作用,我们还需要在spring bean配置文件中启用基于注释的配置。这可以通过context:annotation-config元素或通过定义类型的bean来完成org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
。
@Qualifier
annotation - 此注释用于避免bean映射中的冲突,我们需要提供将用于自动装配的bean名称。这样我们就可以避免为同一类型定义多个bean的问题。此注释通常与@Autowired注释一起使用。对于具有多个参数的构造函数,我们可以将此注释与方法中的参数名称一起使用。默认情况下,Spring bean自动装配已关闭。Spring bean autowire默认值为“default”,表示不执行自动装配。autowire值“no”也有相同的行为。
为了展示Spring Bean自动装配的使用,让我们创建一个简单的Spring Maven项目。我们的最终项目将如下图所示。
让我们逐个研究每个autowire选项。为此,我们将创建一个Model bean和一个服务类,我们将在其中注入模型bean。
对于spring自动装配,我们不需要添加任何其他依赖项。我们的pom.xml文件具有spring框架核心依赖关系,如下所示。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.springframework.samplesgroupId>
<artifactId>SpringBeanAutowiringartifactId>
<version>0.0.1-SNAPSHOTversion>
<properties>
<java.version>1.6java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-framework.version>4.0.2.RELEASEspring-framework.version>
<logback.version>1.0.13logback.version>
<slf4j.version>1.7.5slf4j.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>${slf4j.version}version>
<scope>compilescope>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>${logback.version}version>
<scope>runtimescope>
dependency>
dependencies>
project>
让我们创建一个名为Employee的简单Java Bean。这个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自动装配注入Employee bean。
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;
}
}
我们将使用相同的服务类来执行Spring自动装配byName,byType和构造函数。setter方法将用于弹簧自动装配byName和byType,而基于构造函数的注入将由构造函数autowire属性使用。
当我们使用spring autowire byName或byType时,使用默认构造函数。这就是我们为EmployeeService bean明确定义默认构造函数的原因。
让我们用Spring @Autowired注释创建一个单独的类,用于自动装配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;
}
}
请注意,我已经使用Spring @Autowired注释注释了Employee变量和它的setter方法,但是只有其中一个足以用于spring bean自动装配。
让我们创建另一个服务类,我们将使用@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 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;
}
}
当这个bean将被Spring框架初始化时,名为“employee”的bean将用于自动装配。Spring @Autowired注释除了一个参数“required”,它是一个布尔值,默认值为TRUE。我们可以将它定义为“false”,这样如果找不到适合自动装配的bean,spring框架就不会抛出任何异常。
Spring bean配置文件是任何spring应用程序的主要部分,让我们看一下spring bean配置文件的外观,然后我们将查看它的每个部分。
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-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>
<bean name="employeeServiceByName" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="byName" />
<bean name="employeeServiceByType" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="byType" />
<bean name="employeeServiceConstructor" class="com.journaldev.spring.autowiring.service.EmployeeService" autowire="constructor" />
<context:annotation-config />
<bean name="employeeAutowiredByTypeService" class="com.journaldev.spring.autowiring.service.EmployeeAutowiredByTypeService" />
<bean name="employeeAutowiredByConstructorService" class="com.journaldev.spring.autowiring.service.EmployeeAutowiredByConstructorService" />
beans>
关于spring bean配置文件的重点是:
default-autowire
用于定义默认的自动装配方法。在这里,我将默认的自动装配方法定义为byName。default-autowire-candidates
用于为可用于自动装配的bean名称提供模式。为简单起见,我允许所有bean定义都符合自动装配的条件,但是如果我们可以为自动装配定义一些模式。例如,如果我们只想要自动装配DAO bean定义,我们可以将其指定为default-autowire-candidates="*DAO"
。autowire-candidate="false"
用于bean定义,使其不符合自动装配的条件。当我们为单个类型提供多个bean定义时,它们很有用,我们希望其中一些不是自动装配的。例如,在上面的spring bean配置中,“employee1”bean不会用于自动装配。context:annotation-config
用于启用基于注释的配置支持。请注意,employeeAutowiredByTypeService和employeeAutowiredByConstructorService bean没有autowire属性。既然我们的弹簧应用已经准备好了所有类型的弹簧自动装配,那么让我们编写一个简单的测试程序,看看它是否按预期工作。
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();
}
}
程序很简单,我们只是创建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
正如您所看到的,对于autowire byName和byType,默认的no-args构造函数用于初始化bean。对于构造函数的autowire,使用基于参数的构造函数。
从所有变量的哈希码,我们已经确认所有的spring bean都是不同的对象,而不是指同一个对象。
由于我们从符合条件的bean列表中删除了“employee1”以进行自动装配,因此bean映射中没有混淆。如果我们autowire-candidate="false"
从“employee1”定义中删除,我们将在执行上述main方法时得到以下错误消息。
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.(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.(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 Annotation和Spring自动装配功能的全部内容,请从下面链接下载示例项目并进行分析以了解更多信息。