Spring 配置使用 - Bean 自动装配

基本概念

自动装配(autowire),意味着整个装配过程是自动完成,而不再由我们手动去指定。

在 Spring 中自动装配共有以下几种方式:

名称说明
no表示不使用自动装配,此时必须手动指定依赖的 Bean
byName根据属性名自动装配,默认会检查整个容器中与属性名称相同的 Bean 标识。
byType根据属性的类型自动装配,默认会检查整个容器与属性类型相同的 Bean。
constructor与 byType 相似,同样是根据类型自动装配,不同的是这里匹配的是构造参数的类型,主要用于 constructor(构造) 注入
default与 beans 标签的 default-autowire 属性有关
autodetect判断 Bean 的构造方法是否存在构造参数,若有则采用 constructor 自动装配,否则采用 byType 自动装配。目前已过时,Spring 3.0 以后不再被使用

no

意味着不使用自动装配,采用手动配置的方式。这里以构造注入为例,介绍下手动装配的过程:

  • 首先定义用的 Bean
public class Cat{public class Animals {
    public Animals(Cat cat){ }
}
  • 在 xml 配置文件中定义
<bean id="cat" class="com.demo.Cat" />

<!-- ①手动装配,必须手动指定成员变量的依赖 Bean  -->
<bean id="animals" class="com.demo.Animals" >
    <constructor-arg name="cat" ref="cat"/>
</bean>

<!-- ②同样意味这此时 autowire 属性为 no ,同 ① 作用一样 -->
<bean id="animals" class="com.demo.Animals" autowire="no">
    <constructor-arg name="cat" ref="cat"/>
</bean>
  • 创建容器验证
public static void main(String [ ] args) {
    String location = ...
    ApplicationContext factory = new FileSystemXmlApplicationContext(location);
}

byName

根据属性名自动装配,默认会检查整个容器中与属性名称相同的 Bean 标识(包括 id,name,alias),并且该方式只适用于 setter 注入

  • 定义 Bean
public class Cat{public class Animals {
    private Cat cat;
    //省略 sertter/getter...
}
  • 在 xml 配置文件中定义
<bean id="cat" class="com.demo.Cat" />

<!-- 与手动装配相比,减少了配置的工作量 -->
<bean id="animals" class="com.demo.Animals" autowire="byName"/>
  • 调用验证
String location = ...
ApplicationContext factory = new FileSystemXmlApplicationContext(location);
Animals animals = (Animals) factory.getBean("animals");
System.out.println(animals.getCat());

需要注意的是,当容器中不存在标识与属性名匹配的 bean 时,容器默认不会抛出异常,而是将属性当作 null 对待,即在调用 get 方法时默认输出 null。该特性同样适用于所有的 setter 注入


byType

根据属性的类型自动装配,默认会检查整个容器与属性类型相同的 Bean,该方式只适用于 setter 注入

同 byName 的自动装配方式相似,该方式的配置仅仅是将 byName 替换成 byType 而已,如下所示:

<bean id="animals" class="com.demo.Animals" autowire="byType"/>

但是该方式存在着一个巨大的隐患,我们知道 byName 是通过在容器中查找与属性名称相同的 Bean,由于 Spring 容器的限制,是不允许存在两个标识相同的 bean,因此通过该方式匹配的结果默认只有一个匹配的 Bean。

但是 byType 不一样,Spring 容器并没有限制相同类型 Bean 的存在,只要它们的标识不一样,即是合理的。下面来探究下这种情况:

  • 定义 Bean
public class Cat{public class Animals {
    private Cat cat;
    //省略 sertter/getter...
}
  • 在 xml 配置文件中定义
<!-- ①存在多个类型相同,标识不同的 Bean -->
<bean id="cat1" class="com.demo.Cat" />
<bean id="cat2" class="com.demo.Cat" />

<!-- ②即便不指定标识,Spring 也自动生成不同的标识,作用同 ① -->
<bean  class="com.demo.Cat" />
<bean  class="com.demo.Cat" />

<bean id="animals" class="com.demo.Animals" autowire="byType"/>
  • 创建容器验证

此时会抛出如下异常信息:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type...

这是不是意味着在使用 byType 自动装配时,容器中就不能存在相同类型的 Bean 呢,答案当然是否定的,Spring 通过引入竞选机制来解决这一问题。


1.primary

当一个 Bean 将 primary 标识为 true,就表示自己是主要的的 Bean,该值默认为 flase。当存在多个相同类型的 Bean 时,自动装配时会优先选择它。

<!-- 正确 -->
<bean  class="com.demo.Cat" primary="true" />
<bean  class="com.demo.Cat" />

<!-- 错误 -->
<bean  class="com.demo.Cat" primary="false" />
<bean  class="com.demo.Cat" />

<!-- 错误 -->
<bean  class="com.demo.Cat" primary="true" />
<bean  class="com.demo.Cat" primary="true" />

2.autowire-candidate

与 primary 意思相同,当一个 Bean 将 autowire-candidate 标识为 false,就表示自己不再是候选的的 Bean,而是主要的 Bean ,该值默认为 true,defalut。当存在多个相同类型的 Bean 时,自动装配时会优先选择该属性为 false 的 Bean。

<!-- 正确 -->
<bean  class="com.demo.Cat" autowire-candidate="false" />
<bean  class="com.demo.Cat" />

<!-- 错误 -->
<bean  class="com.demo.Cat" autowire-candidate="true" />
<bean  class="com.demo.Cat" />

<!-- 错误 -->
<bean  class="com.demo.Cat" autowire-candidate="default" />
<bean  class="com.demo.Cat" />

<!-- 错误 -->
<bean  class="com.demo.Cat" autowire-candidate="ture" />
<bean  class="com.demo.Cat" autowire-candidate="default"/>

constructor

与 byType 相似,同样是根据类型自动装配,不同的是这里匹配的是构造参数的类型,主要用于 constructor(构造) 注入。

  • 定义 Bean
public class Cat{public class Animals {
    public Animals(Cat cat){ }
}
  • 在 xml 配置文件中定义
<bean  class="com.controller.Cat"  />

<bean id="animals" class="com.demo.Animals" autowire="constructor"/>

同样该方式也存在相同类型 Bean 的隐患,解决方法与 byType 一致,通过 primary、autowire-candidate

需要注意的是,与 byName 、byType 不同的是,该方式采用的构造注入,而不是 setter 注入。若 Bean 中没有定义无参构造函数时,若在自动装配时找不到匹配的 Bean,则会抛出异常。而不会像 byName 、byType 把它当作 null 处理。


default

与 bean 的父标签 beans 的 default-autowire 属性有关,同 autowire 一致,该属性也有 no、default、byType、byName、constructor 这几个值。

假设 beans 的 default-autowire 为 byType,则表示 bean 标签中 autowire 为 default 都默认采用 byType 的注入方式。

具体配置形式如下:

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd" 
    default-autowire="byType">

    <bean  class="com.controller.Cat"  />

    <!-- 此时采用 byType 的自动装配方式 -->
    <bean id="animals" class="com.demo.Animals" autowire="default"/>
</beans> 

autodetect

判断 Bean 的构造方法是否存在构造参数,若有则采用 constructor 自动装配,否则采用 byType 自动装配。

Spring 3.0 以后该方式已被抛弃,这里就不再探究。若想要配置该注入方式,需要要把3.0的 xsd 替换为 2.5 的 xsd,否则会报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oxf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值