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 ...
随机推荐
- JVM插码之三:javaagent介绍及javassist介绍
本文介绍一下,当下比较基础但是使用场景却很多的一种技术,稍微偏底层点,就是字节码插庄技术了...,如果之前大家熟悉了asm,cglib以及javassit等技术,那么下面说的就很简单了...,因为下面 ...
- Spark Streaming之六:Transformations 普通的转换操作
与RDD类似,DStream也提供了自己的一系列操作方法,这些操作可以分成四类: Transformations 普通的转换操作 Window Operations 窗口转换操作 Join Opera ...
- j++与++j
(j++)+(++j)+(++j) 核心部分汇编代码 执行顺序j原始值为5,存放在栈的ebp-4中;q无初始值,存放在栈的ebp-8中先执行一次j自增赋值++j ;j=6执行第一个加法运算;值存放在C ...
- Visual Studio的输出窗口上输出调试信息的函数
Visual Studio的输出窗口上输出文字的函数 参考网站:http://www.voidcn.com/blog/u011808175/article/p-2083567.html 当你编写非控制 ...
- R语言:文本(字符串)处理与正则表达式
R语言:文本(字符串)处理与正则表达式 (2014-03-27 16:40:44) 转载▼ 标签: 教育 分类: R 处理文本是每一种计算机语言都应该具备的功能,但不是每一种语言都侧重于处理文本.R语 ...
- 12、scala隐式转换与隐式参数
一.隐式转换 1.介绍 Scala提供的隐式转换和隐式参数功能,是非常有特色的功能.是Java等编程语言所没有的功能.它可以允许你手动指定,将某种类型的对象转换成其他类型的对象. 通过这些功能,可以实 ...
- JAVA 框架 / SSM / SSM SPRING+SPING MVC + MYBATIS 三大框架整合详细步骤
http://how2j.cn/k/ssm/ssm-tutorial/1137.html
- Struts2学习第三课 Struts2详解
接着上次的课程 这次我们看struts.xml 修改如下:这里是加上命名空间,默认的是不加,我们手动加上时就要在访问时加上命名空间. <?xml version="1.0" ...
- Umbraco安装过程中出现的问题以及调试
在VS2015中使用NuGet安装完UmbracoCms后,按Ctrl+F5运行程序来完成安装UmbracoCms的过程中,发现一直在安装但是没有反应 估计是出现了错误.所以我到项目所在的文件夹中查找 ...
- JWT使用过程中遇到的问题
1.创建token的盐设置过于简单,出现secret key byte array cannot be null or empty. 异常 解决方法:jwt:config:key:hwy ------ ...