ApplicationContext(三)BeanFactory 初始化

上节我们提到容器初始化的第一步首先进行了属性的检验,下面就要开始第二步:进行 beanFactory 的初始化工作了。

ApplicationContext 是对 BeanFactory 的功能上的扩展,不但包含了 BeanFactory 的全部功能更在其基础上添加了大量的扩展应用,那么 obtainFreshBeanFactory 正是实现 BeanFactory ,并对配置文件进行解析。

源代码【AbstractApplicationContext】

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 初始化 BeanFactory,并进行 XML 文件读取,并将得到的 BeanFactory 记录在当前实体的属性中
refreshBeanFactory();
// 返回当前实体的 BeanFactory 属性
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
return beanFactory;
}

很明显这段代码没有做什么事,将其主要的工作都委托给了 refreshBeanFactory() 方法,这个方法由其子类实现。

源代码【AbstractRefreshableApplicationContext】

protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 1. 创建 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory(); // 为了序列化指定id,如果需要的话,让这个 beanFactory 从 id 反序列化到 BeanFactory 对象
beanFactory.setSerializationId(getId());
// 2. 定制 beanFactory,如设置:①是否允许同名覆盖、②是否允许循环依赖
customizeBeanFactory(beanFactory);
// 3. 初始化 DocumentReader,并进行 XML 文件读取及解析
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

在 refreshBeanFactory() 方法中主要做了三件事:

(1) 创建 BeanFactory。创建前需要先销毁以前的 beanFactory。

(2) 定制 BeanFactory。设置了是否允许同名覆盖、是否允许循环依赖两个属性。你可能会奇怪,这两个属性本来就是 null,没有值,这是在干什么?还是那名话,需要子类来覆盖。

(3) 加载 BeanFactory 配置文件。解析 xml 文件,加载 BeanDefinition。

一、创建 BeanFactory

protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

二、定制 BeanFactory

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}

三、加载 BeanDefinition

源代码【AbstractXmlApplicationContext】

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 1. 创建 XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // 2. 对 beanDefinitionReader 进行环境变量的设置
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // 3. 对 beanDefinitionReader 进行设置,默认可以覆盖
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
} protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
reader.setValidating(this.validating);
}

在初始化了 DefaultListableBeanfactory 和 XmlBeanDefinitionReader,后就可以进行配置文件的读取了。

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader)
throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}

使用 XmlBeanDefinitionReader 的 loadBeanDefinitions 方法进行配置文件的加载机注册相信大家已经不陌生,这完全就是开始 BeanFactory 的套路。因为在 XmlBeanDefinitionReader 中已经将之前初始化的 DefaultlistableBeanfactory 注册进去了,所以 XmlBeanDefinitionReader 所读取的 BeanDefinitionHolder 都会注册到 DefaultListableBeanfactory 中。

此时的 BeanFactory 已经解析了所有的 BeanDefinition,可以进行 bean 的加载了,不过在加载前 Spring 还做了一些其它的工作。


每天用心记录一点点。内容也许不重要,但习惯很重要!

ApplicationContext(三)BeanFactory 初始化的更多相关文章

  1. Spring中ApplicationContext和beanfactory区别---解析二

    一.BeanFactory 和ApplicationContext Bean 工厂(com.springframework.beans.factory.BeanFactory)是Spring 框架最核 ...

  2. 创建ApplicationContext与BeanFactory时的区别-Spring源码学习之容器的基本实现

    传送门 可以加载XML两种方法 使用 BeanFactory 加载 XML BeanFactory bf = new XmlBeanFactory(new ClassPathResource(&quo ...

  3. Spring BeanFactory 初始化 和 Bean 生命周期

    (version:spring-context-4.3.15.RELEASE) AbstractApplicationContext#refresh() public void refresh() t ...

  4. 关于java中三种初始化块的执行顺序

    许多小伙伴对于java中的三种初始化块的执行顺序一直感到头疼,接下来我们就来分析一下这三种初始化块到底是怎么运行的.有些公司也会将这个问题作为笔试题目. 下面通过一段代码来看看创建对象时这么初始化块是 ...

  5. DirectX11笔记(三)--Direct3D初始化代码

    原文:DirectX11笔记(三)--Direct3D初始化代码 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u010333737/article ...

  6. DirectX11笔记(三)--Direct3D初始化2

    原文:DirectX11笔记(三)--Direct3D初始化2 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u010333737/article/ ...

  7. 面试题:ApplicationContext和BeanFactory两种容器区别

    ApplicationContext和BeanFactory两种容器区别 BeanFactory是ApplicationContext容器的父接口 BeanFactory(多例模式): BeanFac ...

  8. Day008 三种初始化及内存分析

    三种初始化和内存分析 Java内存分析: 堆: 存放new的对象和数组. 可以被所有的线程共享,不会存放别的对象引用. 栈: 存放基本变量类型(会包含这个基本类型的具体数值). 引用对象的变量(会存放 ...

  9. Java数组02——三种初始化及内存分析

    内存分析 三种初始化 例子  package array; ​ public class ArrayDemon02 {     public static void main(String[] arg ...

随机推荐

  1. RGB图片取大于阈值部分

    #include<opencv2\opencv.hpp> #include <iostream> using namespace cv; using namespace std ...

  2. 1.5.1、CDH 搭建Hadoop在安装之前(定制安装解决方案---使用内部包裹存储库)

    使用内部包裹存储库 您可以通过托管内部存储库或手动将存储库文件复制到Cloudera Manager主机来为Cloudera Manager创建parcel存储库. 继续阅读: 托管内部包裹存储库 配 ...

  3. EVIL TWIN AP

    git clone https://github.com/P0cL4bs/3vilTwinAttacker.git cd 3vilTwinAttacker/ ./installer.sh --inst ...

  4. sqlserver 查看当前连接数

    参考 https://www.cnblogs.com/lumnm/archive/2009/08/29/1556349.html SELECT * FROM[Master].[dbo].[SYSPRO ...

  5. zabbix主动监测客户端设置

    主动/被动模式 主动模式和被动模式的区别一开始我也非常模糊,其实这是zabbix的两种工作方式,是相对于zabbix的agent端来说的,定义为: 主动模式:zabbix的agent端,也就是客户端, ...

  6. Python 学习笔记---爬取海贼王动漫

    最近无聊整理的爬虫代码,可以自动爬取腾讯动漫的任意漫画,思路如下: 1. 先获取想下载的动漫url, 这里用了 getUrls ,直接获取动漫的最后一章 2. 然后进入到该动漫去获取要下载的图片url ...

  7. e-olymp Problem9 N-digit numbers(打表)

    传送门:点我 N-digit numbers Find the quantity of N-digit numbers, which the sum is equal to their product ...

  8. 第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛----随手记录帖

    这是跟学长学姐组队来打的最爽的一次比赛了,也可能是互相组队最后一次比赛了,南哥和楼学姐,省赛之后就退役了,祝他们能考研和面试都有happy ending! 虽然最后没有把F题的n^2约数的数学题写完, ...

  9. PHP连接数据库(mysql)

    前端链接后台,数据库几乎必不可少.所以本文总结了PHP链接数据库的常用方法步骤. 首先 链接数据库:mysqli_connect参数①主机地址 ②mysql用户名③nysql密码④选择连接的数据库⑤端 ...

  10. AngulairJS表单输入验证与mvc

    AngulairJS表单输入验证 1.表单中,常用的验证操作有:$dirty 表单有填写记录.$valid 字段内容合法的.$invalid 字段内容是非法的.$pristine 表单没有填写记录.$ ...