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 ...
随机推荐
- Python xlrd、xlwt、xlutils修改Excel文件-OK
一.xlrd读取excel 这里介绍一个不错的包xlrs,可以工作在任何平台.这也就意味着你可以在Linux下读取Excel文件. 首先,打开workbook: import xlrdwb = ...
- 【转】 Pro Android学习笔记(三四):Menu(5):动态菜单
目录(?)[-] OptionsMenu的创建方式 如何再次创建OptionsMenu 每次访问都重新填充菜单项 OptionsMenu的创建方式 OptionMenu在第一次访问该菜单时调用,只调用 ...
- Mybatis下面的MapperScannerConfigurer 扫描器
Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring Mybatis在与Spring集成的时候可以配置 Ma ...
- eclipse tomcat 无法加载导入的web项目,There are no resources that can be added or removed from the server. .
应该是项目自己的setting文件夹下的描述信息和.project文件的描述信息,不能适用于这个eclipse和tomcat. 解决方法: 1,找相同类型的工程(tomcat能引用的)2,把新建项目里 ...
- 又来一波!Android精品源码分享
今天又汇总了几个不错的源码给大家!希望能帮到需要的小伙伴~话不多少,直接上源码! 1.Android精品源码:拖动条控件实现源码 此次分享的源码是一个不错的Android控件,建议大家可以细致的看下. ...
- python-queue知识点
1.dict获取value dict.get(key_name)2.三元运算 res,err=stdout.read(),stderr.read() #三元运算 result=res if res e ...
- [dp]编辑距离问题
https://www.51nod.com/tutorial/course.html#!courseId=3 转移方程: 注意如何对齐的. 这个算法的特点是,S和T字符串左边始终是对齐的.为了更好地理 ...
- Flask06 地址约定、利用falsk提供的方法渲染模板
1 访问地址约定 在访问路径的末尾是否需要加 / -> 可以加,也可以不加 前端的访问路径必须和后端的路径完全匹配才能够访问成功,如果我们在后台的路径都是以 / 结尾,但是我们的访问路径是没有以 ...
- leetcode:7. Reverse Integer
这题简单,也花了我好长时间,我自己写的code比较麻烦,也没啥技巧:按正负性分类执行,先转化成字符串,用stringbuilder进行旋转,如果超出范围了就用try catch public int ...
- kingadmin
kingadmin 是一个模拟 Django admin 开发的后台管理系统,可以用来嵌套在其他的项目中作为单独的 app 程序存在. 执行流程 1.项目启动,开始执行 app_setup.py 文件 ...