Autowired Spring注解用于Autowired@automatic dependency。Spring框架是建立在依赖注入我们通过Spring Bean配置文件注入类依赖关系。
目录
Spring@Autowired注解
通常我们在Spring Bean配置文件中提供bean配置的详细信息,并且我们还指定将使用ref
attribute. But Spring framework provides autowiring features too where we don’t need to provide bean injection details explicitly.
我们可以通过不同的方法自动连接Spring Bean。
- autowire byName–对于这种类型的自动连接,setter方法用于依赖注入。同样,在我们将注入依赖关系的类和Spring Bean配置文件中,变量名应该相同。
- autowire byType–;对于这种类型的自动布线,使用class type。因此,在Spring Bean配置文件中,应该只有一个为这种类型配置的bean。
- autowire by constructor–;这几乎与autowire byType类似,唯一的区别是构造函数用于注入依赖项。
- 如果autowire 3的autowire选项中有一个是autowire,则可以使用autowire。此选项用于按构造函数或按类型的autowire,由Spring容器确定。因为我们已经有太多的选择,这个选项是不推荐的。在本教程中,我将不介绍此选项。
@Autowired
annotation – We can use Spring @Autowired annotation for spring bean autowiring. @Autowired annotation can be applied on variables and methods for autowiring byType. We can also use @Autowired annotation on constructor for constructor based spring autowiring.为了让@Autowired注解正常工作,我们还需要在Spring Bean配置文件中启用基于注解的配置。这可以通过上下文:注解配置元素或通过定义类型的bean
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
.@Qualifier
annotation – This annotation is used to avoid conflicts in bean mapping and we need to provide the bean name that will be used for autowiring. This way we can avoid issues where multiple beans are defined for same type. This annotation usually works with the @Autowired annotation. For constructors with multiple arguments, we can use this annotation with the argument names in the method.
默认情况下,Spring Bean的自动连接是关闭的。Spring Bean的autowire默认值是“;默认值”;这意味着不执行自动连接。autowire值“;no”;也有相同的行为。
为了展示Spring Bean自动布线的使用,让我们创建一个简单的springmaven项目。我们的最终项目将如下图所示。
让我们逐一了解每个autowire选项。为此,我们将创建一个模型bean和一个服务类,我们将在其中注入模型bean。
Spring@Autowired注解和Maven依赖项
对于spring autowiring,我们不需要添加任何额外的依赖项。我们的pom.xml文件文件具有springframework核心依赖项,如下所示。
<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
让我们创建一个简单的javabean,名为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注解和服务类
让我们创建我们的服务类,在这个类中,我们将通过springautowiring注入employeebean。
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自动连接。setter方法将用于spring的byName和byType自动连接,而基于构造函数的注入将由构造函数autowire属性使用。
当我们按名称或类型使用spring autowire时,使用默认构造函数。这就是为什么我们为EmployeeService bean显式定义了默认构造函数。
Spring@Autowired注解和#8211;autowiring byType示例
让我们用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 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变量和it的setter方法,但是对于Spring Bean的自动连接,只有其中一个足够了。
Spring@Autowired注解和@Qualifier 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注解除了一个参数“;必选”;这是一个默认值为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">
<property name="name" value="Pankaj"></property>
</bean>
<bean name="employee1" 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" autowire="byName" />
<!-- autowiring byType, there should be only one bean definition for the mapping -->
<bean name="employeeServiceByType" autowire="byType" />
<!-- autowiring by constructor -->
<bean name="employeeServiceConstructor" autowire="constructor" />
<!-- Enable Annotation based configuration -->
<context:annotation-config />
<!-- using @Autowiring annotation in below beans, byType and constructor -->
<bean name="employeeAutowiredByTypeService" />
<bean name="employeeAutowiredByConstructorService" />
</beans>
关于Spring Bean配置文件的要点是:
- 豆要素
default-autowire
is used to define the default autowiring method. Here I am defining the default autowiring method to be byName. - 豆要素
default-autowire-candidates
is used to provide the pattern for bean names that can be used for autowiring. For simplicity I am allowing all the bean definitions to be eligible for autowiring, however if we can define some pattern for autowiring. For example, if we want only DAO bean definitions for autowiring, we can specify it asdefault-autowire-candidates="*DAO"
. autowire-candidate="false"
is used in a bean definition to make it ineligible for autowiring. It’s useful when we have multiple bean definitions for a single type and we want some of them not to be autowired. For example, in above spring bean configurations “employee1” bean will not be used for autowiring.- autowire属性byName、byType和constructor是可以自行理解的,这里没有什么要解释的。
context:annotation-config
is used to enable annotation based configuration support. Notice that employeeAutowiredByTypeService and employeeAutowiredByConstructorService beans don’t have autowire attributes.
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());
//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,使用基于参数的构造函数。
从所有变量的hashcode中,我们已经确认了所有Spring Bean都是不同的对象,并且没有引用同一个对象。
由于我们从自动连接的合格bean列表中删除了&;employee1”;,因此bean映射没有出现混乱。如果我们移除autowire-candidate="false"
from the “employee1” definition, we will get below error message when executing the above main method.
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 autowiring特性的全部,请从下面的链接下载示例项目并对其进行分析以了解更多信息。