在Spring IOC容器的设计中,可以看到两个主要的容器系列,一个是实现BeanFactory接口的简单容器系列,这系列容器只实现了容器的最基本功能;另一个是ApplicationContext应用上下文,它作为容器的高级形态而存在。应用上下文在简单容器的基础上,增加了许多面向框架的特性,同时对应用环境做了许多适配。
1 BeanFactory
1.1 BeanFactory的应用场景
BeanFactory接口的第一行有这样一段代码
<span style="font-size:18px;">String FACTORY_BEAN_PREFIX = "&";</span>
它定义了一个转义字符“&”,用来区分通过容器获取FactoryBean产生的对象和获取FactoryBean本身。例如,myFactory是一个FactoryBean,那么使用“&myFactory”得到的是FactoryBean,而不是myFactory产生的对象。
这BeanFactory接口中,定义了如下方法:
- BeanFactory接口设计了getBean方法,这个方法是使用IoC容器API的主要方法,通过这个方法,可以取得IoC容器中管理的Bean,Bean的取得是通过指定名字来索引的。如果需要在获取Bean时对Bean的类型进行检查,BeanFactory接口定义了带有参数的getBean方法,这个方法的使用与不带参数的getBean方法类似,不同的是增加了对Bean检索的类型的要求。
Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
- 通过接口方法containsBean让用户能够判断容器是否含有指定名字的Bean。
<span style="font-size:18px;">boolean containsBean(String name);</span>
- 通过接口方法isSingleton来查询指定名字的Bean是否是Singleton类型的Bean。对于Singleton属性,用户可以在BeanDefinition中指定。
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
- 通过接口方法isPrototype来查询指定名字的Bean是否是prototype类型的。与Singleton属性一样,这个属性也可以由用户在BeanDefinition中指定。
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
- 通过接口方法isTypeMatch来查询指定了名字的Bean的Class类型是否是特定的Class类型。这个Class类型可以由用户来指定。
boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
- 通过接口方法getType来查询指定名字的Bean的Class类型。
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
- 通过接口方法getAliases来查询指定了名字的Bean的所有别名,这些别名都是用户在BeanDefinition中定义的。
String[] getAliases(String name);
1.2BeanFactory 容器的设计原理
XMLBeanFactory是BeanFactory的最简单、也是常用的实现类
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* Create a new XmlBeanFactory with the given resource,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
/**
* Create a new XmlBeanFactory with the given input stream,
* which must be parsable using DOM.
* @param resource XML resource to load bean definitions from
* @param parentBeanFactory parent bean factory
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
它继承自DefaultListableBeanFactory这个类,在Spring中,实际上是把DefaultListableBeanFactory作为一个默认的功能完整的IoC容器来使用的。XmlBeanFactory在继承了DefaultListableBeanFactory容器的功能的同时,增加了新的功能,那就是解析XML文件来初始化BeanFactory。
根据源码可以看出,XMLBeanFactory的构造需要指定BeanDefinition 的来源,这个源自于Resouce的封装。这样IOC容器就可以利用BeanDefinition进行容器的初始化和依赖注入过程。
实际上整个BeanFactory的构建过程由如下几步完成
(1) 指定一个BeanDefinition的来源,这里用的是Resouce类
(2) 定义一个IOC容器,即XMLBeanFactory ,也可以认为是DefaultListableBeanFactory,这时这个容器还是空的,里面什么都没有
(3) 需要在BeanDefinition和IOC容器之间建立起关系,在XMLBeanFactory中使用的是XmlBeanDefinitionReader,它将完成完成IOC容器的配置,这个时候IOC容器就建立完成。
在BeanFactory的初始化时候,不会初始化所有的Bean,而是在getBean的时候才进行Bean的初始化
2 ApplicationContext
这是BeanFactory的继承体系中,一个位于中间位置的接口,它在BeanFactory的基础上,提供了一些更高级的功能。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver
- 支持不同的信息源。我们看到ApplicationContext扩展了MessageSource接口,这些信息源的扩展功能可以支持国际化的实现,为开发多语言版本的应用提供服务。
- 访问资源。这一特性体现在对ResourceLoader和Resource的支持上,这样我们可以从不同地方得到Bean定义资源。这种抽象使用户程序可以灵活地定义Bean定义信息,尤其是从不同的I/O途径得到Bean定义信息。这在接口关系上看不出来,不过一般来说,具体ApplicationContext都是继承了DefaultResourceLoader的子类。因为DefaultResourceLoader是AbstractApplicationContext的基类,关于Resource在IoC容器中的使用,后面会有详细的讲解。
- 支持应用事件。继承了接口ApplicationEventPublisher,从而在上下文中引入了事件机制。这些事件和Bean的生命周期的结合为Bean的管理提供了便利。
- 在ApplicationContext中提供的附加服务。这些服务使得基本IoC容器的功能更丰富。因为具备了这些丰富的附加功能,使得ApplicationContext与简单的BeanFactory相比,对它的使用是一种面向框架的使用风格,所以一般建议在开发应用时使用ApplicationContext作为IoC容器的基本形式。
ApplicationContext的常用实现类是ClassPathXmlApplicationContext, FileSystemXmlApplicationContext和AnnotationConfigApplicationContext,如果在Web中使用Spring容器,则通常有XmlWebApplicationContext和AnnotationConfigWebApplicationContext两个实现类。
在ApplicationContext初始化时,默认会预初始化所有的sigletonBean。这意味着在系统创建ApplicationContext时有较大的开销