04.Spring Ioc 容器 - 刷新
基本概念
Spring Ioc 容器被创建之后,接下来就是它的初始化过程了。该过程包含了配置、刷新两个步骤
。
刷新由 Spring 容器自己实现,具体发生在 ConfigurableApplicationContext 的 refresh 方法中。
首先来看该接口的继承关系:
由于这里 Spring 的配置文件采用 xml 形式,所以 Ioc 容器的类型默认为 XmlWebApplicationContext。接下来就以该类的 refresh 方法为入口,探究下 Ioc 容器的刷新过程。
原理分析
该类的 refresh 方法继承自己父类 AbstractApplicationContext,观察代码可以发现该方法包含了众多方法,这里只探究下 1、2 过程。
private final Object startupShutdownMonitor = new Object();
public void refresh() throws BeansException, IllegalStateException {
// 加锁
synchronized (this.startupShutdownMonitor) {
// 1.准备刷新
prepareRefresh();
// 2.创建内部容器,该容器负责 Bean 的创建与管理
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
} catch (BeansException ex) {
// 省略代码...
destroyBeans();
cancelRefresh(ex);
throw ex;
} finally {
resetCommonCaches();
}
}
}
准备刷新
初始化准备,即为 Ioc 容器的初始化过程做准备,该过程与 Spring 的 Environment 有关,这里暂不探究。
// 容器早期发布事件集
private Set<ApplicationEvent> earlyApplicationEvents;
protected void prepareRefresh() {
// 省略部分代码...
// 1.激活容器
this.active.set(true);
// 2.初始化 Environment 的 propertySources 属性
initPropertySources();
// 3.校验 Environment 的 requiredProperties 是否都存在
getEnvironment().validateRequiredProperties();
// 4.创建事件集合
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
来看下 initPropertySources 这个方法, 它与 Spring 容器的 Environment 有关:
protected void initPropertySources() {
// 取得配置过程中创建的容器环境
ConfigurableEnvironment env = getEnvironment();
// 初始化 Environment 的 propertySources 属性
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).
initPropertySources(this.servletContext, this.servletConfig);
}
}
创建内部容器
之前介绍过 ApplicationContext 对象里面会包含了一个 BeanFactory 对象。有关 Bean 的基本功能是调用内部的 BeanFactory 对象来实现的。
在这里, BeanFactory 具体指的是 ConfigurableListableBeanFactory ,来看它们的继承关系:
下面来看 obtainFreshBeanFactory 的具体实现:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 1.刷新 BeanFactory
refreshBeanFactory();
// 2.取得 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 省略部分代码...
return beanFactory;
}
1.刷新 BeanFactory
下面来看刷新内部 BeanFactory 的实现过程:
protected final void refreshBeanFactory() throws BeansException {
// 1.判断是否存在 Beanfactory ,存在则销毁并关闭它
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 2.创建 BeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 3.设置 BeanFactory 的 id,同它外部的 Spring 容器一致
beanFactory.setSerializationId(getId());
// 4.定制 BeanFactory 初始化,暂不探究
customizeBeanFactory(beanFactory);
// 5.加载 Bean 实例
loadBeanDefinitions(beanFactory);
// 6.将 BeanFactory 设置为 Spring 容器的内部 BeanFactory
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}catch (IOException ex) {
// 抛出异常...
}
}
①判断是否存在 BeanFactory,存在则销毁、关闭容器的内部 BeanFactory
// 1.判断是否存在存在内部 BeanFactory
protected final boolean hasBeanFactory() {
synchronized (this.beanFactoryMonitor) {
return (this.beanFactory != null);
}
}
// 2.若存在销毁内部 BeanFactory 的所有 Bean
protected void destroyBeans() {
getBeanFactory().destroySingletons();
}
// 2.关闭 内部 BeanFactory
protected final void closeBeanFactory() {
synchronized (this.beanFactoryMonitor) {
this.beanFactory.setSerializationId(null);
this.beanFactory = null;
}
}
②创建 BeanFactory,这里会默认创建 DefaultListableBeanFactory 类作为内部容器(内部 BeanFactory)。
protected DefaultListableBeanFactory createBeanFactory() {
// 1.取得内部 BeanFactory 的父容器
// 2.创建内部 BeanFactory
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
protected BeanFactory getInternalParentBeanFactory() {
// 判断取得 Spring 容器的父容器类型
// 匹配,则返回父容器内部 BeanFactory,否则返回父容器
return (getParent() instanceof ConfigurableApplicationContext) ?
((ConfigurableApplicationContext) getParent()).getBeanFactory() :getParent();
}
public DefaultListableBeanFactory(BeanFactory parentBeanFactory) {
super(parentBeanFactory);
}
public AbstractAutowireCapableBeanFactory(BeanFactory parentBeanFactory) {
this();
setParentBeanFactory(parentBeanFactory);
}
③加载 Bean 实例,该过程由 BeanDefinitionReader 负责,下篇在详细分析。
2.取得 BeanFactory
// 取得 BeanFactory
public final ConfigurableListableBeanFactory getBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory == null) {
// 抛出异常...
}
return this.beanFactory;
}
}
总结
下面通过流程图来总结下 Spring Ioc 容器的初始化过程:
04.Spring Ioc 容器 - 刷新的更多相关文章
- Spring IoC 容器的扩展
前言 本篇文章主要介绍 Spring 中 BeanFactory 的扩展 ApplicationContext,我们平时日常开发中也基本上是使用它,不会去直接使用 BeanFactory. 那么在 S ...
- Spring IoC容器的初始化过程
Spring IoC容器的初始化包括 BeanDefinition的Resource定位.载入和注册 这三个基本的过程.IoC容器的初始化过程不包含Bean依赖注入的实现.Bean依赖的注入一般会发生 ...
- 对Spring IoC容器实现的结构分析
本文的目标:从实现的角度来认识SpringIoC容器. 观察的角度:从外部接口,内部实现,组成部分,执行过程四个方面来认识SpringIoC容器. 本文的风格:首先列出SpringIoC的外部接口及内 ...
- Spring源码分析:Spring IOC容器初始化
概述: Spring 对于Java 开发来说,以及算得上非常基础并且核心的框架了,在有一定开发经验后,阅读源码能更好的提高我们的编码能力并且让我们对其更加理解.俗话说知己知彼,百战不殆.当你对Spri ...
- Spring IOC容器基本原理
2.2.1 IOC容器的概念IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.应用程序无需直接在代码中new相关的对象,应用程序由IOC容器 ...
- 1.3浅谈Spring(IOC容器的实现)
这一节我们来讨论IOC容器到底做了什么. 还是借用之前的那段代码 ClassPathXmlApplicationContext app = new ClassPathXmlApplicationCon ...
- Spring IOC容器启动流程源码解析(一)——容器概念详解及源码初探
目录 1. 前言 1.1 IOC容器到底是什么 1.2 BeanFactory和ApplicationContext的联系以及区别 1.3 解读IOC容器启动流程的意义 1.4 如何有效的阅读源码 2 ...
- Spring IOC容器在Web容器中是怎样启动的
前言 我们一般都知道怎样使用spring来开发web应用后,但对spring的内部实现机制通常不是很明白.这里从源码角度分析下Spring是怎样启动的.在讲spring启动之前,我们先来看看一个web ...
- 03.Spring IoC 容器 - 初始化
基本概念 Spring IoC 容器的初始化过程在监听器 ContextLoaderListener 类中定义. 具体由该类的的 configureAndRefreshWebApplicationCo ...
随机推荐
- Javascript:必须知道的Javascript知识点之“单线程事件驱动”
heiboard: Javascript:必须知道的Javascript知识点之“单线程事件驱动”
- AD9 如何画4层pcb板
新建的PCB文件默认的是2层板,教你怎么设置4层甚至更多层板. 在工具栏点击Design-->Layer Stack Manager.进入之后显示的是两层板,添加为4层板,一般是先点top la ...
- java基础知识(11)---多线程
多线程: 进程:正在进行中的程序.其实进程就是一个应用程序运行时的内存分配空间. 线程:其实就是进程中一个程序执行控制单元,一条执行路径.进程负责的是应用程序的空间的标示.线程负责的是应用程序的执行顺 ...
- [FATAL_ERROR] Uncaught PDOException: There is already an active transaction
[FATAL_ERROR] Uncaught PDOException: There is already an active transaction ... $mysql->beginTran ...
- day01_虚拟机与主机之间ip配置
虚拟机1: centos_ node1 虚拟机2:centos_node2 宿主主机虚拟机ip配置: vmnet1 来自为知笔记(Wiz)
- C++之string类
1.String对象的初始化 string s1; 默认构造函数,s1为空串 string s4(n, 'c'); 将s4初始化为字符c的n个副本 string s ...
- C++经典问题:狐狸找兔子
问题描述: 围绕着山顶有10个洞,一只狐狸和一只兔子住在各自的洞里.狐狸想吃掉兔子.一天,兔子对狐狸说:"你想吃我有一个条件,先把洞从1-10编上号,你从10号洞出发,先到1号洞找我:第二次 ...
- 在PCL中如何实现点云压缩(1)
点云由庞大的数据集组成,这些数据集通过距离.颜色.法线等附加信息来描述空间三维点.此外,点云能以非常高的速率被创建出来,因此需要占用相当大的存储资源,一旦点云需要存储或者通过速率受限制的通信信道进行传 ...
- <c和指针>学习笔记5动态内存分配和预处理器
1 动态内存 比如声明数组得时候,我们需要提前预估数组长度,分配大了浪费,少了就更不好操作了.从而引入动态分配,需要的时候再分配. (1)malloc和free void *malloc(size_t ...
- Struts2学习第五课 通过和ServletAPI耦合的方式获取WEB资源
与Servlet耦合的访问方式 直接访问Servlet API将使Action与环境Servlet环境耦合在一起,测试时需要有Servlet容器,不便对Action的单元测试. 直接获取HttpSer ...