自动装配协作者

Spring 容器可以自动装配协作者(Collaborators)之间的关系。你可以让 Spring 通过检查 ApplicationContext 的内容,自动为你的 bean 解析协作者(其他 bean)。自动装配具有以下优点:

  • 自动装配可以显著减少指定属性或构造函数参数的需求。(本章其他地方讨论过的 bean 模板等其他机制在这方面也很有价值。)

  • 自动装配可以在对象演进时更新配置。例如,如果你需要向一个类添加依赖项,该依赖项可以自动满足,而无需修改配置。因此,自动装配在开发过程中特别有用,并且不排斥在代码库变得更稳定时切换到显式装配的选项。

使用基于 XML 的配置元数据时(参见依赖注入),你可以通过 `` 元素的 autowire 属性指定 bean 定义的自动装配模式。自动装配功能有四种模式。你可以为每个 bean 指定自动装配,因此可以选择哪些 bean 进行自动装配。下表描述了四种自动装配模式:

表 1. 自动装配模式
模式 说明

no

(默认) 不进行自动装配。Bean 引用必须由 ref 元素定义。对于大型部署,不建议更改此默认设置,因为显式指定协作者提供了更好的控制和清晰度。在某种程度上,它记录了系统的结构。

byName

按属性名自动装配。Spring 会查找与需要自动装配的属性同名的 bean。例如,如果一个 bean 定义被设置为按名称自动装配,并且它包含一个 master 属性(即它有一个 setMaster(..) 方法),Spring 会查找名为 master 的 bean 定义并用它来设置该属性。

byType

如果容器中存在 *正好一个* 属性类型的 bean,则允许自动装配该属性。如果存在多个,则会抛出致命异常,这表明你不能对该 bean 使用 byType 自动装配。如果没有匹配的 bean,则不会发生任何事情(属性未设置)。

constructor

类似于 byType,但应用于构造函数参数。如果容器中不存在 *正好一个* 构造函数参数类型的 bean,则会引发致命错误。

使用 byTypeconstructor 自动装配模式时,你可以装配数组和带类型的集合。在这种情况下,容器中所有与期望类型匹配的自动装配候选者都会被提供来满足依赖。如果期望的键类型是 String,你可以自动装配强类型的 Map 实例。自动装配的 Map 实例的值包含所有匹配期望类型的 bean 实例,而 Map 实例的键包含相应的 bean 名称。

自动装配的限制和缺点

自动装配在整个项目中一致使用时效果最佳。如果通常不使用自动装配,而只对一两个 bean 定义使用,可能会让开发者感到困惑。

考虑自动装配的限制和缺点:

  • propertyconstructor-arg 设置中的显式依赖项总是会覆盖自动装配。你不能自动装配基本类型、StringsClasses 等简单属性(以及这些简单属性的数组)。此限制是设计使然。

  • 自动装配不如显式装配精确。尽管正如前面表格中提到的,Spring 在可能出现意外结果的歧义情况下会谨慎地避免猜测。你的 Spring 管理的对象之间的关系不再被显式地记录。

  • 装配信息可能对从 Spring 容器生成文档的工具不可用。

  • 容器中的多个 bean 定义可能与 setter 方法或要自动装配的构造函数参数指定的类型匹配。对于数组、集合或 Map 实例,这不一定是个问题。然而,对于期望单个值的依赖项,这种歧义不会被随意解决。如果没有唯一的 bean 定义可用,则会抛出异常。

在后一种情况下,你有几种选择:

  • 放弃自动装配,转而使用显式装配。

  • 通过将 bean 定义的 autowire-candidate 属性设置为 false 来避免该 bean 的自动装配,如下一节所述。

  • 通过将 `` 元素的 primary 属性设置为 true,将单个 bean 定义指定为主要候选者。

  • 实现基于注解的配置提供的更细粒度的控制,如基于注解的容器配置中所述。

排除 Bean 的自动装配

对于每个 bean,你可以将它排除在自动装配之外。在 Spring 的 XML 格式中,将 `` 元素的 autowire-candidate 属性设置为 false;对于 `@Bean` 注解,该属性名为 autowireCandidate。容器会使该特定的 bean 定义对自动装配基础设施不可用,包括基于注解的注入点,例如 `@Autowired`

autowire-candidate 属性旨在只影响基于类型的自动装配。它不影响按名称进行的显式引用,即使指定的 bean 未标记为自动装配候选者,按名称引用也会解析。因此,如果名称匹配,按名称自动装配仍然会注入 bean。

你还可以根据 bean 名称的模式匹配来限制自动装配候选者。顶级 `` 元素在其 default-autowire-candidates 属性中接受一个或多个模式。例如,要将自动装配候选者状态限制为名称以 Repository 结尾的任何 bean,请提供 *Repository 的值。要提供多个模式,请将它们定义为逗号分隔的列表。对于 bean 定义的 autowire-candidate 属性,明确的 truefalse 值总是优先。对于这些 bean,模式匹配规则不适用。

这些技术对于你永远不想通过自动装配注入到其他 bean 中的 bean 非常有用。这并不意味着被排除的 bean 本身不能使用自动装配进行配置。而是说,该 bean 本身不是自动装配其他 bean 的候选者。

从 6.2 版本开始,`@Bean` 方法支持自动装配候选者标志的两种变体:`autowireCandidate` 和 `defaultCandidate`。

当使用限定符(qualifiers)时,标记为 `defaultCandidate=false` 的 bean 仅在存在额外限定符指示的注入点可用。这对于那些应该在特定区域可注入但又不希望影响其他位置同类型 bean 的受限委托非常有用。这样的 bean 绝不会仅按声明类型注入,而是按类型加上特定限定符注入。

相比之下,`autowireCandidate=false` 的行为与上面解释的 `autowire-candidate` 属性完全相同:这样的 bean 将永远不会按类型注入。