BeanFactory与ApplicationContext的区别-Spring源码学习之容器的基本实现

可以加载XML两种方法

使用 BeanFactory 加载 XML

1
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicaitonContext.xml"));

Ps:因为我是跟着《Spring源码深度解析》学习的,而这本书出版在13年9月,这一种方法在新的Spring版本中已经废弃掉了,取而代之的是下面的方法;但既然学了,那就还是记录一下,学习一下开发者的思想也是不错的.

使用 ApplicationContext 加载 XML

1
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

相同点

上述两者都是通过加载XMl配置文件的方式加载Bean,而后者是前者的扩展,提供了更多的功能,即ApplicationContext拥有BeanFactory的全部功能,在绝大多数的”典型的”企业应用和系统,ApplicationContext都优先于BeanFactory.

不同点

BeanFactory是延迟加载,如果一个Bean当中存在属性没有加载,会在第一次调用getBean()方法的时候报错,而ApplicationContext会在读取Xml文件后,如果配置文件没有错误,就会将所有的Bean加载到内存中,缺点就是在Bean较多的时候比较占内存,程序启动较慢.

Spring容器加载中最重要的两个类

DefaultListableBeanFactory

XmlBeanFactory继承自DefaultListableBeanFactory,而后者是整个Bean加载的核心部分,是Spring注册及加载Bean的默认实现,而XmlBeanFactory使用了自定义的Xml读取器XmlBeanDefinitionReader,实现了个性化的BeanDefinitionReader读取.

XmlBeanDefinitionReader

主要负责Xml文件的读取、解析和注册功能


加载时的区别

上面的两种方法的处理大致相同,让我们通过时序图看看两者在加载时的区别:

1
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicaitonContext.xml"));

粗略时序图:

image
首先,将applicationContext.xmlClassPathResource进行封装得到Resource资源,Resource接口将所有的资源文件统一处理,当通过Resource相关类完成了对配置文件的封装之后,就由XmlBeanDefinitionReader进行读取和解析.

1
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

粗略时序图:

image
附上ClassPathXmlApplicatioContext构造函数的源码:

1
2
3
4
5
6
7
8
9
10
11
12
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent)
throws BeansException {
super(parent);
Assert.notNull(paths, "Path array must not be null");
Assert.notNull(clazz, "Class argument must not be null");
this.configResources = new Resource[paths.length]; //创建资源数组 private Resource[] configResources;
for (int i = 0; i < paths.length; i++) {
this.configResources[i] = new ClassPathResource(paths[i], clazz);
}
refresh(); //解析工作,ClassPathXmlApplicatioContext继承来自AbstractApplicationContext中的方法
}

首先,同样是封装配置文件,但封装完成之后并没有直接进行读取,而是调用了refresh()方法(这个方法里面进行了很多操作,扩展的功能几乎是在这里面实现的),refresh()方法中的obtainFreshBeanFactory()方法负责初始化BeanFactory,并对XMl文件读取,读取的核心实现是该方法中调用的refreshBeanFactory()方法,这个方法再调用图中的loadBeanDefinitions(beanFactory)方法(由于板面原因,没有画出),然后在其中创建XmlBeanDefinitionReader对象,再将最初封装的资源文件数组进行依次读取并解析.

二者在后面的Xml解析工作都几乎是一样的,都采用了SAX解析,区别就在于解析之前的准备和解析之后的完善工作.

文章目录
  1. 1. 可以加载XML两种方法
    1. 1.1. 使用 BeanFactory 加载 XML
    2. 1.2. 使用 ApplicationContext 加载 XML
    3. 1.3. 相同点
    4. 1.4. 不同点
  2. 2. Spring容器加载中最重要的两个类
    1. 2.1. DefaultListableBeanFactory
    2. 2.2. XmlBeanDefinitionReader
  3. 3. 加载时的区别
|