3.2 Spring IoC容器的类型
Spring IoC容器提供两种基本的容器类型:BeanFactory和ApplicationContext。在Spring中,BeanFactory是IoC容器的实际代表者。
3.2.1 BeanFactory
BeanFactory是基础类型的IoC容器,提供基本的容器服务。如果没有特殊指定,BeanFactory采用延迟初始化策略,也就是当客户端需要容器中某个对象时,才对该受管理的对象初始化并进行依赖注入操作。相对来说,BeanFactory容器启动较快,所需资源有限。对于资源有限并且功能要求不严格的场景,使用BeanFactory容器是比较合适的。
BeanFactory也可以说是Spring的“心脏”,Spring使用BeanFactory来实例化、配置和管理Bean。
Spring Bean的创建是典型的工厂模式,这一系列的Bean工厂为程序开发人员管理对象间的依赖关系提供了很多便利和基础服务。BeanFactory作为最顶层的一个接口类,定义了IoC容器的基本功能规范。BeanFactory有三个子类:ListableBeanFactory、HierarchicalBeanFactory和AutowireCapable BeanFactory,最终的默认实现类是DefaultListableBeanFactory,它实现了所有的接口。为什么要定义这么多层次的接口呢?查阅这些接口的源代码和说明可以发现,每个接口都有它使用的场合,以区分在对象的传递和转化过程中,对对象的数据访问所做的限制。例如,ListableBeanFactory接口表示这些Bean是可列表的;HierarchicalBeanFactory接口表示这些Bean是有继承关系的,即每个Bean有可能有父Bean;AutowireCapableBeanFactory接口定义Bean的自动装配规则。这四个接口共同定义了Bean的集合、Bean之间的关系和Bean的行为。
最基本的IoC容器接口类BeanFactory的代码如下:
3.2.2 BeanFactory容器的设计原理
在BeanFactory接口的基础上,Spring提供了一系列容器的实现方式,供程序开发人员使用。我们以XmlBeanFactory的实现为例,简单说明IoC容器的设计原理。
XmlBeanFactory继承自DefaultListableBeanFactory类,同时实现了其他诸如XML读取的附加功能。也就是说,XmlBeanFactory是一个可以读取以XML文件方式定义的BeanDefinition的IoC容器。
XmlBeanDefinitionReader代码如下:
在XmlBeanFactory中,初始化了一个XmlBeanDefinitionReader对象,由它来完成XML形式的信息处理。构造XmlBeanFactory容器时,需要指定BeanDefinition的信息来源,将它封装成Spring中的Resource类,然后传递给XmlBeanFactory构造函数,IoC容器就可以方便地定位到需要的BeanDefinition信息来对Bean完成容器的初始化和依赖注入过程。对XmlBeanDefinitionReader对象的初始化以及使用这个对象来完成loadBeanDefinitions调用的过程,就是这个调用启动从Resource中载入BeanDefinitions的过程。
3.2.3 ApplicationContext
如果说BeanFactory是Spring的“心脏”,那么ApplicationContext就是Spring的“躯体”。Application Context由BeanFactory派生而来,提供了更多面向实际应用的功能。ApplicationContext是在BeanFactory基础上构建的,是一个比较高级的容器,除了拥有BeanFactory的全部功能外,也提供其他高级特性,如MessageSource(国际化资源接口)、ResourceLoader(资源加载接口)、ApplicationEventPublisher(应用事件发布接口)等。ApplicationContext所管理的对象默认在ApplicationContext启动之后全部初始化并绑定完成,所以其启动较慢,占用资源较多。在系统资源充足并需要提供较多功能的使用场景,ApplicationContext是一个不错的选择。
BeanFactory接口提供了配置框架及基本功能,但是无法支持Spring的AOP功能和Web应用。ApplicationContext接口作为BeanFactory的派生,提供BeanFactory所有的功能,而且还在功能上做了扩展。与BeanFactory相比,ApplicationContext还提供了以下功能。
(1)MessageSource,访问国际化信息的接口。
(2)资源访问,如URL和文件。
(3)事件传播特性,即支持AOP特性。
(4)载入多个有继承关系的上下文,使每一个上下文都专注于一个特定的层次,比如应用的Web层。
3.2.4 ApplicationContext容器的设计原理
通常以常用的FileSystemXmlApplicationContext的实现为例,说明ApplicationContext容器的设计原理,代码如下:
在FileSystemXmlApplicationContext的设计中,可以看到ApplicationContext应用上下文的主要功能已经在FileSystemXmlApplicationContext的基类AbstractXmlApplicationContext中实现了,FileSystemXml ApplicationContext作为一个具体的应用上下文,只需要实现与它自身设计相关的两个功能:一是,如果应用直接使用FileSystemXmlApplicationContext,对于实例化这个应用上下文的支持,同时启动IoC容器的refresh()过程;二是,与FileSystemXmlApplicationContext设计相关的具体功能,这部分与怎样从文件系统中加载XML的Bean定义资源有关。
3.2.5 BeanFactory和ApplicationContext的区别
BeanFactory和ApplicationContext都是通过XML配置文件加载Bean,与BeanFactory相比,Application Context提供了更多的扩展功能,但其主要区别在于BeanFactory是延迟加载。如果Bean的某一个属性没有注入,BeanFactory加载后,直至第一次调用getBean方法才会抛出异常;而ApplicationContext则在初始化自身时进行检验,这样有利于检查所依赖属性是否注入。所以,通常情况下我们选择使用ApplicationContext。
下面介绍两者的XML配置的不同之处。使用BeanFactory从XML配置文件加载Bean,代码如下:
使用ApplicationContext从XML配置文件加载Bean,代码如下:
(1)BeanFactroy采用延迟加载形式注入Bean,即只有在使用某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样就不能发现Spring的配置问题。而ApplicationContext则相反,它是在容器启动时一次性创建了所有的Bean。这样,在容器启动时就可以发现Spring中存在的配置错误。相对于基本的BeanFactory,ApplicationContext唯一的不足是占用内存空间,当应用程序配置Bean较多时,程序启动较慢。
(2)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,两者的区别是BeanFactory需要手动注册,而ApplicationContext则是自动注册。与BeanFactory相比,Application Context加入了一些更好用的功能。BeanFactory的许多功能需要通过编程实现,而ApplicationContext可以通过配置实现。比如后处理Bean,ApplicationContext直接配置在配置文件即可,而BeanFactory要在代码中写出来才可以被容器识别。
(3)BeanFactory主要面对Spring框架的基础设施,而ApplicationContext主要面对使用Spring的开发者。基本上,开发者都会使用ApplicationContext而并非BeanFactory。