基本概念

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. Python xlrd、xlwt、xlutils修改Excel文件-OK

    一.xlrd读取excel 这里介绍一个不错的包xlrs,可以工作在任何平台.这也就意味着你可以在Linux下读取Excel文件. 首先,打开workbook:    import xlrdwb = ...

  2. 【转】 Pro Android学习笔记(三四):Menu(5):动态菜单

    目录(?)[-] OptionsMenu的创建方式 如何再次创建OptionsMenu 每次访问都重新填充菜单项 OptionsMenu的创建方式 OptionMenu在第一次访问该菜单时调用,只调用 ...

  3. Mybatis下面的MapperScannerConfigurer 扫描器

    Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring Mybatis在与Spring集成的时候可以配置              Ma ...

  4. eclipse tomcat 无法加载导入的web项目,There are no resources that can be added or removed from the server. .

    应该是项目自己的setting文件夹下的描述信息和.project文件的描述信息,不能适用于这个eclipse和tomcat. 解决方法: 1,找相同类型的工程(tomcat能引用的)2,把新建项目里 ...

  5. 又来一波!Android精品源码分享

    今天又汇总了几个不错的源码给大家!希望能帮到需要的小伙伴~话不多少,直接上源码! 1.Android精品源码:拖动条控件实现源码 此次分享的源码是一个不错的Android控件,建议大家可以细致的看下. ...

  6. python-queue知识点

    1.dict获取value dict.get(key_name)2.三元运算 res,err=stdout.read(),stderr.read() #三元运算 result=res if res e ...

  7. [dp]编辑距离问题

    https://www.51nod.com/tutorial/course.html#!courseId=3 转移方程: 注意如何对齐的. 这个算法的特点是,S和T字符串左边始终是对齐的.为了更好地理 ...

  8. Flask06 地址约定、利用falsk提供的方法渲染模板

    1 访问地址约定 在访问路径的末尾是否需要加 / -> 可以加,也可以不加 前端的访问路径必须和后端的路径完全匹配才能够访问成功,如果我们在后台的路径都是以 / 结尾,但是我们的访问路径是没有以 ...

  9. leetcode:7. Reverse Integer

    这题简单,也花了我好长时间,我自己写的code比较麻烦,也没啥技巧:按正负性分类执行,先转化成字符串,用stringbuilder进行旋转,如果超出范围了就用try catch public int ...

  10. kingadmin

    kingadmin 是一个模拟 Django admin 开发的后台管理系统,可以用来嵌套在其他的项目中作为单独的 app 程序存在. 执行流程 1.项目启动,开始执行 app_setup.py 文件 ...