第6章 Spring IoC容器之扩展篇
本章内容
- Spring 2.5的基于注解的依赖注入
- Spring 3.0展望
Spring 2.5 的基于注解的依赖注入
Spring2.5提供的 基于注解的依赖注入 功能延续了Spring框架内在IoC容器设计与实现上的一致性。除了依赖关系的“表达”方式上的不同,底层的实现机制基本上保持一致。
如果我们已经从Spring的IoC容器的XML之旅中成功走过来,那么在体验基于注解的依赖注入的过程中,一定会发现许多似曾相识的身影。你瞧,基于XML配置方式的自动绑定功能,就是我们再次邂逅的第一位老朋友…
注解版的自动绑定( @Autowired )
1. 从自动绑定(autowire)到@Autowired
在使用依赖注入绑定FXNews相关实现类时,为了减少配置量,我们可以采用Spring的IoC容器提供的自动绑定功能,如下所示:
可以通过<beans>
的default-autowire
来指定默认的自动绑定方式,也可以通过每个bean定义上的autowire
来指定每个bean定义各自的自动绑定方式,它们都是触发容器对相应对象给予依赖注入的标志。
而将自动绑定的标志用注解来表示时,也就得到了基于注解的依赖注入,或者更确切地称为基于注解的自动绑定。
@Autowired
是基于注解的依赖注入的核心注解,它的存在可以让容器知道需要为当前类注入哪些依赖。比如可以使用@Autowired
对FXNewsProvider类进行标注,以表明要为FXNewsProvider注入的依赖。
下方代码给出了标注后的情况。
与原有的byType类型的自动绑定方式类似,@Autowired
也是按照类型匹配进行依赖注入的,只不过,它要比byType更加灵活,也更加强大。@Autowired
可以标注于类定义的多个位置,包括如下几个。
**域(Filed)或者说属性(Property)。**不管它们声明的访问限制符是private
、protected
还是public
,只要标注了@Autowired
,它们所需要的依赖注入需求就都能够被满足,如下所示:
**构造方法定义(Constructor)。**标注于类的构造方法之上的@Autowired
,相当于抢夺了原有自动绑定功能中“constructor”方式的权利,它将根据构造方法参数类型,来决定将什么样的依赖对象注入给当前对象。从最初的代码示例中,我们可以看到标注于构造方法之上的@Autowired
的用法。
方法定义(Method)。@Autowired
不仅可以标注于传统的setter方法之上,而且还可以标注于任意名称的方法定义之上,只要该方法定义了需要被注入的参数。下方代码给出了一个标注于这种任意名称方法之上的@Autowired
使用示例代码。
现在,虽然可以随意地在类定义的各种合适的地方标注@Autowired
,希望这些被@Autowired
标注的依赖能够被注入,但是,仅将@Autowired
标注于类定义中并不能让Spring的IoC容器聪明到自己去查看这些注解,然后注入符合条件的依赖对象。
容器需要某种方式来了解,哪些对象标注了@Autowired
,哪些对象可以作为可供选择的依赖对象来注入给需要的对象。
在考虑使用什么方式实现这一功能之前,我们先比较一下原有的自动绑定功能与使用@Autowired
之后产生了哪些差别。
使用自动绑定的时候,我们将所有对象相关的bean定义追加到了容器的配置文件中,然后使用default-autowire
或者autowire
告知容器,依照这两种属性指定的绑定方式,将容器中各个对象绑定到一起。在使用@Autowired
之后,default-autowire
或者autowire
的职责就转给了@Autowired
,所以,现在,容器的配置文件中就只剩下了一个个孤伶伶的bean定义,如下所示:
为了给容器中定义的每个bean定义对应的实例注入依赖,可以遍历它们,然后通过反射,检查每个bean定义对应的类上各种可能位置上的@Autowired
。如果存在的话,就可以从当前容器管理的对象中获取符合条件的对象,设置给@Autowired
所标注的属性域、构造方法或者方法定义。
整个逻辑如下方代码中的原型代码所示。
看到以上的原型代码所要完成的功能以及我们的设想,你一定想到了,我们可以提供一个Spring的IoC容器使用的BeanPostProcessor
自定义实现,让这个BeanPostProcessor
在实例化bean定义的过程中,来检查当前对象是否有@Autowired
标注的依赖需要注入。
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
就是Spring提供的用于这一目的的BeanPostProcessor
实现。所以,很幸运,我们不用自己去实现它了。
将FXNews相关类定义使用@Autowired
标注之后,只要在IoC容器的配置文件中追加AutowiredAnnotationBeanPostProcessor
就可以让整个应用开始运作了,如下所示:
重点在代码第2行。
当然,这需要我们使用ApplicationContext
类型的容器,否则还得做点儿多余的准备工作。
看着依赖注入相关的信息,一半分散在Java源代码中(@Autowired标注的信息),一半依然留在XML配置文件里,你心里一定觉得很不爽。实际上,我也是,这不是折腾人吗?不过,别急,让我们先解决眼前的另一个问题,稍后再回过头来看看怎么进一步统一这两片国土。
2. @Qualifier 的陪伴
@Autowired
是按照类型进行匹配,如果当前@Autowired
标注的依赖在容器中只能找到一个实例与之对应的话,那还好。可是,要是能够同时找到两个或者多个同一类型的对象实例,又该怎么办呢?我们自己当然知道应该把具体哪个实例注入给当前对象,可是,IoC容器并不知道,所以,得通过某种方式告诉它。这时,就可以使用@Qualifier
对依赖注入的条件做进一步限定,使得容器不再迷茫。
@Qualifier
实际上是byName自动绑定的注解版,既然IoC容器无法自己从多个同一类型的实例中选取我们真正想要的那个,那么我们不妨就使用@Qualifier
直接点名要哪个好了。假设FXNewsProvider
使用的IFXNewsListener
有两个实现,一个是DowJonesNewsListener
,一个是ReutersNewsListener
,二者相关配置如下:
如果我们想让FXNewsProvider
使用ReutersNewsListener
,那么就可以在FXNewsProvider
的类定义中使用@Qualifier
指定这一选择结果,如下:
以上我们使用的是标注于属性域的@Autowired
进行依赖注入。如果使用@Autowired
来标注构造方法或者方法定义的话,同样可以使用@Qualifier
标注方法参数来达到限定注入实例的目的。代码清单6-4给出的正是标注于方法参数之上的@Qualifier
的使用示例。