基本概念

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 容器 - 刷新的更多相关文章

  1. Spring IoC 容器的扩展

    前言 本篇文章主要介绍 Spring 中 BeanFactory 的扩展 ApplicationContext,我们平时日常开发中也基本上是使用它,不会去直接使用 BeanFactory. 那么在 S ...

  2. Spring IoC容器的初始化过程

    Spring IoC容器的初始化包括 BeanDefinition的Resource定位.载入和注册 这三个基本的过程.IoC容器的初始化过程不包含Bean依赖注入的实现.Bean依赖的注入一般会发生 ...

  3. 对Spring IoC容器实现的结构分析

    本文的目标:从实现的角度来认识SpringIoC容器. 观察的角度:从外部接口,内部实现,组成部分,执行过程四个方面来认识SpringIoC容器. 本文的风格:首先列出SpringIoC的外部接口及内 ...

  4. Spring源码分析:Spring IOC容器初始化

    概述: Spring 对于Java 开发来说,以及算得上非常基础并且核心的框架了,在有一定开发经验后,阅读源码能更好的提高我们的编码能力并且让我们对其更加理解.俗话说知己知彼,百战不殆.当你对Spri ...

  5. Spring IOC容器基本原理

    2.2.1 IOC容器的概念IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化.定位.配置应用程序中的对象及建立这些对象间的依赖.应用程序无需直接在代码中new相关的对象,应用程序由IOC容器 ...

  6. 1.3浅谈Spring(IOC容器的实现)

    这一节我们来讨论IOC容器到底做了什么. 还是借用之前的那段代码 ClassPathXmlApplicationContext app = new ClassPathXmlApplicationCon ...

  7. Spring IOC容器启动流程源码解析(一)——容器概念详解及源码初探

    目录 1. 前言 1.1 IOC容器到底是什么 1.2 BeanFactory和ApplicationContext的联系以及区别 1.3 解读IOC容器启动流程的意义 1.4 如何有效的阅读源码 2 ...

  8. Spring IOC容器在Web容器中是怎样启动的

    前言 我们一般都知道怎样使用spring来开发web应用后,但对spring的内部实现机制通常不是很明白.这里从源码角度分析下Spring是怎样启动的.在讲spring启动之前,我们先来看看一个web ...

  9. 03.Spring IoC 容器 - 初始化

    基本概念 Spring IoC 容器的初始化过程在监听器 ContextLoaderListener 类中定义. 具体由该类的的 configureAndRefreshWebApplicationCo ...

随机推荐

  1. 洛谷【P1104】生日(插入排序版)

    题目传送门:https://www.luogu.org/problemnew/show/P1104 题目很简单,我主要是来讲插入排序的. 所谓插入排序,就是从待排序数组不断将数据插入答案数组里. 假设 ...

  2. java.util Properties使用记录

    转:http://www.2cto.com/px/201006/47834.html 在java.util 包下面有一个类 Properties,该类主要用于读取以项目的配置文件(以.properti ...

  3. java代码简单练习

    总结: package com.ds; import java.awt.Color; import java.awt.FlowLayout; import javax.swing.JFrame; im ...

  4. MATLAB模糊逻辑工具箱函数

    说明:本文档中所列出的函数适用于Matlab5.3以上版本,为了简明起见,只列出了函数名,若需要进一步的说明,请参阅MATLAB的帮助文档. 1. GUI工具 Anfisedit      打开ANF ...

  5. 使用SVG + CSS实现动态霓虹灯文字效果

    效果图: 原理:多个SVG描边动画使用不同的animation-delay即可! 对于一个形状SVG元素或文本SVG元素,可以使用stroke-dasharray来控制描边的间隔样式,并且可以用str ...

  6. Python-requests取消SSL验证的警告InsecureRequestWarning解决办法

    使用requests模块请求一个证书无效的网站的话会直接报错 可以设置verify参数为False解决这个问题 # -*- coding:utf-8 -*- __author__ = "Mu ...

  7. JavaScript权威指南读书笔记【第一章】

    第一章 JavaScript概述 前端三大技能: HTML: 描述网页内容 CSS: 描述网页样式 JavaScript: 描述网页行为 特点:动态.弱类型.适合面向对象和函数式编程的风格 语法源自J ...

  8. HTTP之缓存首部

    缓存分好多种:服务器缓存,第三方缓存,浏览器缓存等.其中浏览器缓存是代价最小的,因为浏览器缓存依赖的是客户端,而几乎不耗费服务器端的资源.浏览器做缓存需要给浏览器发送指定的Http头,告诉浏览器缓存多 ...

  9. xdu2017校赛F

    Problem F Dogs of Qwordance Senior Backend R&D Engineers 问题描述 那年夏天,锘爷和杰师傅漫步在知春公园的小道上.他们的妻子.孩子牵 着 ...

  10. python调用Linux下so文件

    1.通过C语言编写一个简单max函数,生成一个max.so链接库 /* * # -shared 为链接库 让编译器知道是要编译一个共享库 * # -fPIC(Position Independent ...