使用@Autowired注解进行Spring自动装配
在Spring框架中,我们提供配置数据,使用这些数据,Spring容器可以实例化bean和注入依赖项。在Spring中自动装配意味着Spring容器可以通过检查ApplicationContext的内容来自动解决bean之间的协作(bean依赖关系)。
Spring自动装配模式
Spring框架中有四种自动装配模式。
否–默认情况下,使用基于XML的配置时没有自动装配。 Bean引用必须由ref元素定义。
byName –在按属性名称自动装配中,Spring查找与需要自动装配的属性同名的bean。例如,如果一个bean包含item属性(即,它具有setItem()方法),Spring将查找一个名为item的bean定义,并使用它来设置该属性。
byType –在自动装配byType中,如果容器中恰好存在一个该属性类型的bean,Spring会自动对属性进行布线。如果存在多个,则会引发致命异常。如果没有匹配的bean,则什么都不会发生(未设置该属性)。
构造函数–构造函数自动装配与byType相似,但适用于构造函数参数。如果容器中不存在构造函数参数类型的一个bean,则将引发致命错误。
Spring自动装配
在Spring中自动装配有三个选项。
我们可以选择使用传统的基于XML的配置自动装配。例如,请参见使用XML配置的Spring自动装配示例。
使用@Autowired注释自动装配。
使用JSR 330的@Inject注释进行自动检测。例如,请参阅使用@Inject和@Named注释进行Spring自动装配。
在这篇文章中,我们将看到使用@Autowired注解的Spring自动装配示例。
启用@Autowired注释
1.我们可以通过注册" AutowiredAnnotationBeanPostProcessor"类在Spring中使用@Autowired注释启用自动装配。
<bean class = "org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
2.通过在基于XML的Spring配置中使用<context:annotation-config />元素。
<context:annotation-config />元素隐式注册后处理器。隐式注册的后处理器包括AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor和前述的RequiredAnnotationBeanPostProcessor。
3.通过在基于XML的Spring配置中使用<context:component-scan>元素。 <context:component-scan>的使用隐式启用<context:annotation-config>元素的功能。大多数情况下,我们将使用此元素。
使用@Autowired注释
我们可以将@Autowired注释应用于构造函数。
我们可以将@Autowired注释应用到setter方法。
我们可以将@Autowired应用于字段。
我们还可以将注释应用于具有任意名称和多个参数的方法。
Spring @Autowired注释示例
我们将使用上述所有选项查看@Autowired的示例。在该示例中,有一个用于下订单的类称为OrderService,可以从商店进行购买。在OrderService类中,必须自动关联商店的依赖关系。
在setter上使用@Autowired注释
setter方法上的@Autowired注释等效于使用配置文件进行自动装配中的autowiring =" byType"。
public interface OrderService { public void buyItems(); }
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowired on Setter @Autowired public void setStore(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
public interface IStore { public void doPurchase(); }
import org.springframework.stereotype.Service; @Service public class RetailStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Retail Store"); } }
XML配置
<?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.xsd"> <context:component-scan base-package="com.theitroad.springproject.service" /> </beans>
我们可以将以下类与main方法一起使用以读取配置并调用bean方法。
public class App { public static void main( String[] args ){ // create context using configuration ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml"); OrderService order = context.getBean(OrderServiceImpl.class); order.buyItems(); // close the context context.close(); } }
在构造函数上使用@Autowired注释
使用配置文件自动装配时,bean的构造函数上的@Autowired注释等效于autowiring =" constructor"。
@Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowired on constructor @Autowired public OrderServiceImpl(IStore store){ this.store = store; } public void buyItems() { store.doPurchase(); } }
如果目标bean只定义了一个构造函数,则不再需要Spring Framework 4.3以及此类构造函数上的@Autowired注释。但是,如果有几个可用的构造函数,则必须至少注释一个,以使容器知道要使用哪个构造函数。
在字段上使用@Autowired注释
使用配置文件进行自动装配时,@ Autowired字段上的注释等效于autowiring =" byType"。
@Service public class OrderServiceImpl implements OrderService { // Autowiring on a field @Autowired private IStore store; public void buyItems() { store.doPurchase(); } }
在任意方法上使用@Autowired注释
我们还可以将注释应用于具有任意名称和多个参数的方法。
@Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowiring on a method @Autowired public void prepare(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
@Autowired的必需属性
默认情况下,当没有匹配的候选bean可用于给定的依赖项时,自动装配将失败。默认行为是将带注释的方法和字段视为必需的依赖项。
例如,在下面的bean类中,如果无法满足对存储的依赖关系,则会引发异常。
@Service public class OrderServiceImpl implements OrderService { @Autowired private IStore store; .. .. }
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderServiceImpl': Unsatisfied dependency expressed through field 'store'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.theitroad.springproject.service.IStore' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
要更改此默认行为,我们可以使用required = false以及@Autowired注释。如果无法自动连线,则忽略该属性。
@Autowired(required = false) private IStore store;
从Spring Framework 5.0开始,我们还可以使用@Nullable注释来指示如果无法自动装配属性,则可以忽略该属性。
@Autowired public void setStore(@Nullable IStore store) { this.store = store; }
使用@Primary和基于注释的自动装配解决冲突
当按类型自动装配时,在这种情况下,Spring容器将无法确定要自动装配哪个bean并抛出NoUniqueBeanDefinitionException。
例如,如果有两个商店的IStore类型为RetailStore和OnlineStore。
@Service public class OnlineStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Online Store"); } }
然后,我们的示例将失败,因为它无法确定要自动关联的商店。
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderServiceImpl': Unsatisfied dependency expressed through method 'setStore' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.theitroad.springproject.service.IStore' available: expected single matching bean but found 2: onlineStore,retailStore
使用Spring的@Primary注释,我们可以更好地控制选择过程。 @Primary表示当多个bean可以自动连接到单值依赖项的候选对象时,应优先使用特定的bean。
通过使用@Primary注释对OnlineStore bean进行注释,可以确保它具有优先级。
@Service @Primary public class OnlineStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Online Store"); } }
使用@Qualifier和基于注释的自动装配来解决冲突
Spring的@Qualifier注释可更好地控制选择过程。我们可以将限定符值与特定的参数相关联,从而缩小类型匹配的范围,以便为每个参数选择特定的bean。
@Service public class OnlineStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Online Store"); } }
@Service public class RetailStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Retail Store"); } }
有两个Istore类型相同的bean,通过使用@Qualifier注释,我们可以限定要自动装配的bean。
@Service public class OrderServiceImpl implements OrderService { private IStore store; @Autowired @Qualifier("retailStore") public void setStore(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
输出:
16:27:57.979 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'onlineStore' 16:27:57.981 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderServiceImpl' 16:27:58.108 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'retailStore' Doing purchase from Retail Store