《Spring攻略(第2版)》——1.11 用XML配置自动装配Bean

简介: 已经看到,如果Spring找到超过一个候选的自动装配Bean,将会抛出UnsatisfiedDependency Exception异常。另一方面,如果自动装配模式设置为byName或byType,而Spring无法找到匹配的Bean进行装配,将把该属性保持为未设置状态,这可能导致一个NullPointerException异常或者一个值没有初始化。

本节书摘来自异步社区《Spring攻略(第2版)》一书中的第1章,第1.11节,作者: 【美】Gary Mak , Josh Long , Daniel Rubio著,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.11 用XML配置自动装配Bean

1.11.1 问题
当一个Bean需要访问另一个Bean时,你可以显式指定引用装配它。但是,如果你的容器能够自动装配Bean,就可以免去手工配置装配的麻烦。

1.11.2 解决方案
Spring IoC容器能够帮助你自动装配Bean。你只要在的autowire属性中指定自动装配模式就可以了。表1-2列出了Spring支持的自动装配模式。
screenshot
*默认模式是no,但是可以设置根元素的default-autowire属性修改。这个默认模式将被Bean自己指定的模式覆盖。

尽管自动装配功能非常强大,但代价是降低了Bean配置的可读性。因为自动装配由Spring在运行时执行,你无法从Bean配置文件中得到Bean装配的方式。在实践中,我们建议仅将自动装配应用到组件依赖不复杂的应用程序中。

1.11.3 工作原理
按照类型的自动装配
你可以将sequenceGenerator bean的autowire属性设置为byType并且不设置prefixGenerator属性。然后,Spring将试图装配类型与PrefixGenerator兼容的Bean。在这个例子中,将自动装配datePrefixGenerator bean。

<beans ...>
   <bean id="sequenceGenerator"
     class="com.apress.springrecipes.sequence.SequenceGenerator"
     autowire="byType">
     <property name="initial" value="100000" />
     <property name="suffix" value="A" />
   </bean>

   <bean id="datePrefixGenerator"
     class="com.apress.springrecipes.sequence.DatePrefixGenerator">
     <property name="pattern" value="yyyyMMdd" />
   </bean>
</beans>

按照类型的自动装配的主要问题是有时候在IoC类型中具有超过一个与目标类型兼容的Bean。在这种情况下,Spring将无法确定哪个Bean最适合于该属性,从而无法进行自动装配。例如,如果你有另一个以当前年份作为前缀的前缀生成器,按照类型的自动装配将会立即被破坏。

<beans ...>
   <bean id="sequenceGenerator"
     class="com.apress.springrecipes.sequence.SequenceGenerator"
     autowire="byType">
     <property name="initial" value="100000" />
     <property name="suffix" value="A" />
   </bean>

   <bean id="datePrefixGenerator"
     class="com.apress.springrecipes.sequence.DatePrefixGenerator">
     <property name="pattern" value="yyyyMMdd" />
   </bean>

   <bean id="yearPrefixGenerator"
     class="com.apress.springrecipes.sequence.DatePrefixGenerator">
     <property name="pattern" value="yyyy" />
   </bean>
</beans>

如果找到超过一个可供自动装配的Bean,Spring将会抛出一个UnsatisfiedDependency Exception异常。

Exception in thread "main"
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sequenceGenerator' defined in class path resource [beans.xml]: Unsatisfied dependency expressed through bean property 'prefixGenerator': No unique bean of type [com.apress.springrecipes.sequence.PrefixGenerator] is defined: expected single matching bean but found 2: [datePrefixGenerator, yearPrefixGenerator]

按照名称的自动装配
byName是另一种自动装配模式,有时候它能解决按照类型的自动装配的问题。它的工作方式与byType类似,但是这时候,Spring将试图装配一个类名与该属性名相同的Bean,而不是兼容的类型。因为Bean的name属性在一个容器中是唯一的,按照名称的自动装配不会导致歧义。

<beans ...>
   <bean id="sequenceGenerator"
     class="com.apress.springrecipes.sequence.SequenceGenerator"
     autowire="byName">
     <property name="initial" value="100000" />
     <property name="suffix" value="A" />
   </bean>

   <bean id="prefixGenerator"
     class="com.apress.springrecipes.sequence.DatePrefixGenerator">
     <property name="pattern" value="yyyyMMdd" />
   </bean>
</beans>

但是,按照名称的自动装配并不能工作于任何情况。有时候,你不可能使目标Bean的名称与属性相同。在实践中,你往往必须在保持其他依赖自动装配的同时明确地指定歧义的依赖。这意味着你混合了显式装配和自动装配。

按照构造程序的自动装配
constructor自动装配模式与byType的工作方式类似,但是更复杂一些。对于具有单个构造程序的Bean,Spring将试图为每个构造程序参数装配一个具有兼容类型的Bean。但是对于具有多个构造程序的Bean,这一过程就更加复杂。Spring首先试图为每个构造程序的每个参数找到一个类型兼容的Bean。然后,将选择具有最多匹配参数的构造程序。

假定SequenceGenerator有一个默认构造程序和一个具有参数PrefixGenerator的构造程序。

package com.apress.springenterpriserecipes.sequence;

public class SequenceGenerator {

   public SequenceGenerator() {}

   public SequenceGenerator(PrefixGenerator prefixGenerator) {
     this.prefixGenerator = prefixGenerator;
   }
   ...
}

在这种情况下,第二个构造程序匹配并且被选中,因为Spring可以找到一个类型与Prefix Generator兼容的Bean。

<beans ...>
   <bean id="sequenceGenerator"
     class="com.apress.springrecipes.sequence.SequenceGenerator"
     autowire="constructor">
     <property name="initial" value="100000" />
     <property name="suffix" value="A" />
   </bean>

   <bean id="datePrefixGenerator"
     class="com.apress.springrecipes.sequence.DatePrefixGenerator">
     <property name="pattern" value="yyyyMMdd" />
   </bean>
</beans>

但是,一个类中的多个构造程序可能造成构造程序参数匹配的歧义。如果你要求Spring确定一个构造程序,情况可能更加复杂。所以,如果你使用这种自动装配模型,就要非常小心地避免歧义。

自动检测的自动装配
自动装配模式autodetect要求Spring在byType和constructor模式中作出决定。如果至少找到一个没有参数的默认构造程序,将选择byType模式,否则,将选择constructor模式。因为SequenceGenerator类定义了默认的构造程序,将选择byType模式。这意味着前缀生成器将通过设值方法注入。

<beans ...>
   <bean id="sequenceGenerator"
     class="com.apress.springrecipes.sequence.SequenceGenerator"
     autowire="autodetect">
     <property name="initial" value="100000" />
     <property name="suffix" value="A" />
   </bean>

   <bean id="datePrefixGenerator"
     class="com.apress.springrecipes.sequence.DatePrefixGenerator">
     <property name="pattern" value="yyyyMMdd" />
   </bean>
</beans>

自动装配与依赖检查
你已经看到,如果Spring找到超过一个候选的自动装配Bean,将会抛出UnsatisfiedDependency Exception异常。另一方面,如果自动装配模式设置为byName或byType,而Spring无法找到匹配的Bean进行装配,将把该属性保持为未设置状态,这可能导致一个NullPointerException异常或者一个值没有初始化。但是,如果你希望在自动装配无法装配的Bean时得到通知,应该将dependency-check属性设置为objects或者all。

在这种情况下,如果自动装配无效将会抛出UnsatisfiedDependencyException异常。objects将通知Spring在相同的Bean工厂中无法找到协同Bean时发出一个错误。all通知容器在任何作为依赖的简单属性类型(String类型或者原始类型)未被设置时发出一个错误,这补充了objects的功能。

<bean id="sequenceGenerator"
   class="com.apress.springrecipes.sequence.SequenceGenerator"
   autowire="byName" dependency-check="objects">
   <property name="initial" value="100000" />
   <property name="suffix" value="A" />
</bean>
相关文章
|
7天前
|
SQL Java 数据库连接
(自用)Spring常用配置
(自用)Spring常用配置
13 0
|
17天前
|
缓存 Java Spring
Spring 框架中 Bean 的生命周期
Spring 框架中 Bean 的生命周期
29 1
|
25天前
|
Java 数据库连接 数据库
hibernate正向生成数据库表以及配置——Teacher.hbm.xml
hibernate正向生成数据库表以及配置——Teacher.hbm.xml
13 1
|
29天前
|
SQL Java 数据库连接
挺详细的spring+springmvc+mybatis配置整合|含源代码
挺详细的spring+springmvc+mybatis配置整合|含源代码
35 1
|
2天前
|
Java 数据库连接 开发者
浅谈Spring的Bean生命周期
浅谈Spring的Bean生命周期
9 1
|
6天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
16 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
6天前
|
JSON Java 数据库连接
属性注入掌握:Spring Boot配置属性的高级技巧与最佳实践
属性注入掌握:Spring Boot配置属性的高级技巧与最佳实践
13 1
|
6天前
|
Java 数据库连接 Spring
简化配置,提高灵活性:Spring中的参数化配置技巧
简化配置,提高灵活性:Spring中的参数化配置技巧
15 0
|
6天前
|
Java Shell 测试技术
一次配置,多场景适用:Spring Boot多套配置文件的深度剖析
一次配置,多场景适用:Spring Boot多套配置文件的深度剖析
16 0
一次配置,多场景适用:Spring Boot多套配置文件的深度剖析
|
10天前
|
Java 容器
SpringBoot使用配置注解开启自动配置功能&整合spring-boot-configuration-processor
SpringBoot使用配置注解开启自动配置功能&整合spring-boot-configuration-processor
12 0