Spring 容器可以自动连接协作 bean 之间的关系。通过检查 ApplicationContext 的内容,您可以让 Spring 为您的bean 自动解析协作者(其他 bean)。自动装配具有以下优点:
- 自动装配可以显著减少指定属性或构造函数参数的需要。(在这方面,本章其他地方讨论的 bean 模板等其他机制也很有价值。)
- 自动装配可以随着对象的发展而更新配置。例如,如果需要向类添加依赖项,则可以自动满足该依赖项,而无需修改配置。因此,在开发过程中,自动装配尤其有用,而不会在代码库变得更稳定时取消切换到显式装配的选项。
当使用基于 xml 的配置元数据(参见依赖注入)时,你可以用 <bean/>
元素中的 autowire 属性。自动装配功能有四种模式。您可以为每个 bean 指定自动装配,并因此可以选择要自动装配的 bean。四种自动装配模式如下表所示:
no | (默认)不自动装配。Bean 引用必须由 ref 元素定义。对于较大的部署,不建议更改默认设置,因为明确指定协作者可以提供更大的控制力和清晰度。在某种程度上,它记录了系统的结构。 |
---|---|
byName | 按属性名称自动装配。Spring 寻找与需要自动装配的属性同名的 bean。例如,如果一个 bean 定义被设置为按名称自动装配并且它包含一个 master 属性(即,它有一个 setMaster(..) 方法),那么 Spring 会查找一个 master 的 bean 并使用它来设置属性。 |
byType | 如果容器中恰好存在一个属性类型的 bean,则让属性自动装配。如果存在多个,则会抛出一个致命异常,这表明您可能不会对该 bean 使用 byType 自动装配。如果没有匹配的 bean,则不会发生任何事情(未设置属性)。 |
constructor | 类似于 byType 但适用于构造函数参数。如果容器中没有一个构造函数参数类型的 bean,则会引发致命错误。 |
看个例子,自动装配是如何使用的
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can inject a MovieFinder
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}
<bean id="simpleMovieLister" class="cn.mrcode.study.springdocsread.SimpleMovieLister"
autowire="byName"></bean>
<bean id="movieFinder" class="cn.mrcode.study.springdocsread.MovieFinder"/>
类里面只有一个普通的 setter 方法,在 xml bean 配置的时候设置 autowire="byName"
,那么 spring 就会尝试找 setter 需要的类型,然后注入。
自动装配的限制和缺点
自动装配在项目中一致使用时效果最佳。如果一般不使用自动装配,开发人员可能会混淆使用它来只装配一个或两个 bean 定义。
考虑自动装配的限制和缺点:
- property 和设置中的显式依赖 constructor-arg 项总是覆盖自动装配。您不能自动装配简单属性,例如基 Strings 和 Classes(以及此类简单属性的数组)。此限制是设计使然。
- 自动装配不如显式装配精确。尽管如前表中所述,Spring 会小心避免猜测可能会产生意想不到的结果的歧义。Spring 管理的对象之间的关系不再明确记录。
- 从 Spring 容器生成文档的工具可能无法使用接线信息。
- 容器内的多个 bean 定义可能与要自动装配的 setter 方法或构造函数参数指定的类型匹配。对于数组、集合或 Map 实例,这不一定是问题。但是,对于期望单个值的依赖项,这种歧义不会被任意解决。如果没有唯一的 bean 定义可用,则会引发异常。
在后一种情况下,您有多种选择:
- 放弃自动装配以支持显式装配。
通过将其 autowire-candidate 属性设置为 false 来避免对 bean 定义进行自动装配
<bean id="simpleMovieLister" class="cn.mrcode.study.springdocsread.SimpleMovieLister"
autowire-candidate="false"></bean>
上面的含义就是:simpleMovieLister 不会参与 自动装配的候选者
通过将其
<bean/>
元素的 primary 属性设置为 true,将单个 bean 定义指定为主要候选者- 使用基于注释的配置实现更细粒度的控制,如 基于注释的容器配置 中所述。
从自动装配中排除 Bean
就是上面那个例子
<bean id="simpleMovieLister" class="cn.mrcode.study.springdocsread.SimpleMovieLister"
autowire-candidate="false"></bean>
上面的含义就是:simpleMovieLister 不会参与 自动装配的候选者 :::tips autowire-candidate 属性旨在仅影响基于类型的自动装配。它不会影响按名称的显式引用,即使指定的 bean 未标记为自动装配候选者,也会得到解析。因此,如果名称匹配,按名称自动装配仍然会注入一个 bean。 :::
还可以设置容器级的配置 default-autowire-candidates
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire-candidates="false"
>
还可以配置通配符方式,例如,要将自动装配候选状态限制为名称以 Repository 结尾的任何 bean,请提供*Repository
, 要提供多种模式,请在逗号分隔的列表中定义它们
这些技术对于您永远不想通过自动装配注入其他 bean 的 bean 很有用。这并不意味着排除的 bean 本身不能通过使用自动装配来配置。相反,bean 本身不是自动装配其他 bean 的候选对象。