7.4.5 自动绑定协作对象

Spring容器可以自动关联协作的bean。可以通过让Spring检查ApplicationContext的内容来自动解析bean的协作者(其他bean)。自动绑定具有以下优点:

  • 自动绑定可以显著减少指定属性或构造方法参数的需要。(其他机制比如在其他章节讨论的bean模板在这方面也是有价值的)
  • 自动绑定可以随着对象的演变而更新配置。例如,如果向一个类添加依赖,则无需修改配置就能自动满足该依赖关系。因此,自动绑定在开发过程中特别有用,当代码库变得更加稳定时也无需切换到显式绑定。

当使用基于XML的配置元数据时,可以使用<bean/>元素的autowire属性为bean定义指定自动绑定模式,自动绑定功能有四种模式。需要为每一个bean指定自动绑定模式,因此可以选择对哪些bean进行自动绑定。

Table 7.2. Autowiring modes

模式 解释
no (默认)不自动绑定。bean的引用必须经由ref元素定义。对于较大的部署不建议更改默认设置,因为显式地指定协作者可以带来更好的控制以及更清晰的描述,某种程度上它记录了系统的结构。
byName 按属性名称自动绑定。Spring会去查找一个与需要自动绑定的属性同名的bean。例如,如果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设置中的显式依赖总是会覆盖自动绑定。不能自动绑定所谓的简单属性,比如基本类型、StringClasses(以及这些简单属性的数组)。这是设计上的局限性。
  • 自动绑定不如显式绑定精确。如上表所示,尽管Spring已经很小心地避免在有歧义可能导致意想不到结果的情况下进行猜测,但是您的被Spring管理的对象之间的关系不再被显式地记录。
  • 从Spring容器生成文档的工具可能无法使用绑定信息。
  • 容器中的多个bean定义可能与由setter方法或构造方法参数指定的类型相匹配以进行自动绑定。对于数组、集合和Map,这不一定有问题。然而,对于一个期待单值的依赖,这种模糊性并不能一下子就解决。如果没有唯一的bean定义可用,则会抛出异常。

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

  • 放弃自动绑定,以显式绑定代之。
  • 如下节所述,通过将其autowire-candidate属性设置为false,避免自动绑定bean定义。
  • 通过设置<bean/>元素的primary属性为true,将单个bean定义指定为首选候选。
  • 使用基于注解的配置实现更细粒度的控制,如7.9节“基于注解的容器配置”中所述

从自动绑定中排除某个bean

以每个bean为单位,您可以从自动绑定中排除一个bean。在Spring的XML格式中,将<bean/>元素的autowire-candidate属性设置为false;容器会使得自动绑定对于这种特殊的bean定义不可用(包括诸如@Autowired之类注解形式的配置)。

autowire-candidate属性被设计用于仅能影响基于类型的自动绑定,而不会影响通过名称的显示引用。通过名称进行引用,即使指定的bean没有标记为自动绑定的候选者,也会正确解析。因此,如果名称匹配,通过名称的自动绑定将注入到bean中。

您也可以基于针对bean名称的模式匹配来限制自动绑定的候选者。顶级<beans/>元素的default-autowire-candidates属性接受一个或多个模式。例如,要将自动绑定的候选者限制为任意名称以Repository结尾的bean,需赋值*Repository。要想匹配多个模式,在定义这些模式时需用逗号分隔。对于一个bean定义的autowire-candidate属性来说,显式地赋值truefalse始终优先处理,对于这样的bean,模式匹配规则不再适用。

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