简述
Spring的IoC容器时一个提供IoC支持的轻量级容器,除了基本的IoC支持,它作为轻量级容器还提供IoC之外的支持。如在Spring的IoC容器之上,Spring还提供相应的AOP框架支持。Spring的IoC容器和IoC Service Provider 所提供的服务之间存在一些二交集,二者的关系如图:
Spring提供了两种容器类型:BeanFactory和ApplicationContext。
- BeanFactory。基础类型IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限,对于资源有限,并且功能要求不是很严格的场景,BeanFactory是比较合适的IoC容器选择。
- ApplicationContext。ApplicationContext在BeanFactory的基础上构建,是相对比较高级的容器实现,除了拥有BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如事件发布、国际化信息支持等,ApplicationContext所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。所以,相对于BeanFactory来说,ApplicationContext要求更多的系统资源,同时,因为在启动时就完成所有初始化,容器启动时间较之BeanFactory也会长一些。在那些系统资源充足,并且要求更多功能的场景中,ApplicationContext类型的容器是比较合适的选择。
BeanFactory, 顾名思义,就是生产Bean的工厂。当然严格来说,这个“生产过程”可不像说起来那么简单,既然Spring的框架提供使用POJO,那么把每个业务对象看作一个JavaBean对象,或许更容易理解为什么Spring的IoC基本容器会起这么一个名字。作为Spring提供的基本IoC容器,BeanFactory可以完成作为IoC Service Provider的所有职责,包括业务对象的注册和对象间依赖关系的绑定。
BeanFactory就像一个汽车生产厂。你从其他汽车零件厂商或者自己的零件生产部门取得汽车零件送入这个汽车生产厂,最后,只需要从生产线的终点取得成品汽车就可以了。相似地,将应用所需要的所有业务对象交给BeanFactory之后,剩下要做的就是直接从BeanFactory取得最终组装完成并且可用的对象,至于这个最终业务对象如何组装,你不需要关心,BeanFactory会搞定。
上面的代码中方法基本是相关查询的方法,例如,取得某个对象的方法(getBean)、查询某个对象是否存在于容器中的方法(containsBean),或者取得某个bean的状态或者类型的方法等。因为通常情况下,对于独立的应用程序,只有主入口类才会跟容器的API直接耦合。
拥有BeanFactory之后的生活
我们有了BeanFactory,我们通常只需要将“生产线图纸”交给BeanFactory,让BeanFactory为我们生产一个FXNewsProvider,如下代码所示:
BeanFactory 的对象注册与依赖绑定方式
BeanFactory作为一个IoC Service Provider ,为了能够明确管理各个业务对象以及对象之间的依赖绑定关系,同样需要某种途径来记录和管理这些信息。
1. 直接编码方式
其实,把编码方式单独提出来称作一种方式并不十分恰当。因为不管什么方式,最终都需要编码才能“落实”所有信息并付诸使用。不过,通过这些代码,起码可以让我们更加清楚BeanFactory在底层是如何运作的。
BeanFactory只是一个接口,我们最终需要一个该接口实现来进行实际的Bean的管理,DefaultListableBeanFactory就是这么一个比较通用的BeanFactory实现类。DefaultListableBeanFactory除了间接地实现了BeanFactory接口,还实现了BeanDefinitionRegistry接口,该接口才是在BeanFactory的实现中担任Bean注册管理的角色。基本上,BeanFactory接口只定义如何访问容器内管理的Bean的方法,各个BeanFactory的具体实现Bean的注册以及管理工作。BeanDefinitionRegistry接口定义抽象Bean的注册逻辑。
这段绑定代码:
- 在main方法中,首先构造一个DefaultListableBeanFactory作为BeanDefinitionRegistry,然后将其交给bindViaCode方法进行具体对象注册和相关依赖管理,然后通过bindViaCode返回的BeanFacotry取得所需要的对象,最后执行相应的逻辑。在我们的实例里,当然就是取得FXNewsProvider进行新闻的处理。
- 在bindViaCode方法中,首先针对相应的业务对象构造与其相对应的BeanDefinition,使用了RootBeanDefinition作为BeanDefinition的实现类。构造完成后,将这些BeanDefinition注册到通过方法参数传进来的BeanDefinitionRegistry中。之后,因为我们的FXNewsProvider是采用的构造方法注入,所以,需要通过ConstructorArgument-Values为其注入相关依赖。在这里为了同时说明Setter方法注入,也同时展示了在Spring中如何使用代码实现setter方法注入。
外部配置文件方式
Spring的IoC容器支持两种配置文件的格式:Properties文件格式和XML文件格式。
XML配置格式的加载
XML配置格式是Spring支持最完整,功能最强大的表达方式。
注解方式
Spring2.5 以后支持基于注解的依赖注入方式,如果不使用classpath-scanning 功能的话,仍然部分依赖于“基于XML配置文件”的依赖注入方式。
@Autowired是这里的主角,它的存在将告知Spring容器需要为当前对象注入哪些依赖对象。而@Component则是配合Spring2.5中新的classpath-scanning(让容器去扫描这个类注入对象)功能使用的。现在我们只需要再向Spring的配置文件中增加一个“触发器”,使用@Autowired和@Component标注的类就能获得依赖对象的注入了。
<context:component-scan / >会到指定的包(package)下面扫描标注有@Component类,如果找到,则将它们添加到容器进行管理,并根据他们标注的@Autowired为这些类注入符合条件的依赖对象。
BeanFactory的XML之旅
和
所有使用XML文件进行配置信息加载的Spring IoC容器,包括BeanFactory和ApplilcationContext 的所有XML相应实现,都使用统一的XML格式。在Spring2.0之前这种格式是由DTD规定,也就是说,所有的Spring容器加载的XML配置文件的头部,都需要以下的DOCTYPE声明:
从Spring2.0版本以后,Spring在继续保持向前兼容的前提下,既可以继续使用DTD方式的DOCTYPE进行配置文件格式的限定,又引入了基于XML Schema的文档声明。所以,Spring 2.0 之后,同样可以使用代码清单展示XSD的文档声明。
不过,不管使用哪种形式的文档声明,实际上限定的元素基本上是相同的。让我们从最顶层元素开始。
- < beans >之唯我独尊
beans 是XML配置文件中最顶层的元素,他下面可以包含0 或者一个< description > 和多个< bean > 以及< import > 或者 < alias >