spring源码之refresh第二篇
大家好,我是程序员田同学
上篇文章对spring核心启动方法refresh做了整体的解读,但是只是泛泛而谈,接下来会出一系统文章对每个方法的源码进行深刻解读。
第一篇文章见 spring源码之方法概览
首先,第一个方法是prepareRefresh()方法,这个方法做的事很简单,也不是本文的重点。该方法记录容器的启动时间,初始化监听容器。
protected void prepareRefresh() {
// Switch to active
//纪录启动时间
this.startupDate = System.currentTimeMillis();
System.out.println("spring启动时间为--------------------" + this.startupDate);
this.closed.set(false);
System.out.println("spring标记为未关闭--------------------" + this.closed);
this.active.set(true);
System.out.println("spring当前激活状态--------------------" + this.active);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
} else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
//空方法
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
//校验 xml配置文件
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
//初始化applicationListeners监听容器
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<> (this.applicationListeners);
} else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
读者大致搂一眼即可,对这个方法整体就能很快把握。
接下来才是今天的重头戏——obtainFreshBeanFactory()方法,是refresh()方法中的第二个方法,也是整个refresh()方法中核心方法之一。
该方法主要的作用是,这里将会初始化 BeanFactory、加载 Bean、注册 Bean 等等。(Bean 并没有完成初始化)
点进去obtainFreshBeanFactory()方法我们一探究竟。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean 等等
refreshBeanFactory();
// 返回刚刚创建的 BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
refreshBeanFactory()应该是这个方法的重头戏,我们再深入进去。
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果 ApplicationContext 中已经加载过 BeanFactory 了,销毁所有 Bean,关闭 BeanFactory
// 注意,应用中 BeanFactory 本来就是可以多个的,这里可不是说应用全局是否有 BeanFactory,而是当前ApplicationContext 是否有 BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 初始化一个 DefaultListableBeanFactory,为什么使用这个BeanFactory?因为这是最牛的 BeanFactory。
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 用于 BeanFactory 的序列化
beanFactory.setSerializationId(getId());
// 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
customizeBeanFactory(beanFactory);
// 加载 Bean 到 BeanFactory 中
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
简单提一句,DefaultListableBeanFactory为什么是最牛的BeanFactory看下这个继承图大概就明了。
// 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
customizeBeanFactory(beanFactory);
这个方式只是一个设置,设置是否允许循环依赖,至于什么是循环依赖呢?也就是 A-B-C之间他们相互依赖,spring有一套自己的机制去处理循环依赖,以后文章为进行分析,这一步仅仅是配置是否允许循环依赖,读者清楚就可以了。
// 这个方法将根据配置,加载各个 Bean,然后放到 BeanFactory 中
loadBeanDefinitions(beanFactory);
经过上面一系列的步骤,一个beandefintion就形成,beandefintion就是我们常说的bean,也就是一个对象的加强版。
接下来就需要把这个bean加入到beanfactory中了,这一步交给loadBeanDefinitions()方法去执行。
spring方法命名确实精妙,只看看方法名大概也知道每个方法干了什么!
创建一个beanDefinitionReader(bean阅读器)去读取xml中的bean,虽然xml很少用了,但是用它来举例还是很经典的。
真正干活的是loadBeanDefinitions(beanDefinitionReader),往下走很漫长漫长,把我们xml中的bean解析成BeanDefinition,并调用registerBeanDefinition()方法把它注册到注册中心,发送注册事件。
总结一下,到这里已经初始化了 Bean 容器,<bean />
配置也相应的转换为了一个个 BeanDefinition,然后注册了各个 BeanDefinition 到注册中心,并且发送了注册事件。
到此obtainFreshBeanFactory() 方法也就正式结束了。
spring的调用过程链路非常非常的长,一步步点进去没一会你就迷了,田同学认为比较好的一个办法就是,先站在方法体外看这个方法干了什么,然后逐步拆分进入到每一个方法中。
站在refresh()外看这两个方法,prepareRefresh()准备一下刷新要做的事,obtainFreshBeanFactory()注册好bean并加入到beanfactory中。
好啦,今天的spring源码分析就到这里了。
spring源码之refresh第二篇的更多相关文章
- 【Spring源码分析】预备篇
前言 最新想学习一下Spring源码,开篇博客记录下学习过程,欢迎一块交流学习. 作为预备篇,主要演示搭建一个最简单的Spring项目样例,对Spring进行最基本梳理. 构建一个最简单的spring ...
- Spring源码解析 | 第二篇:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析
一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
- java架构之路-(spring源码篇)springIOC容器源码解析(上)
我们这次来叭叭一下Spring的源码,这次博客主要来说说Spring源码,先粗略的撸一遍,下篇博客选几个重点去说,由于过于复杂,我也是看了一点点,我们先来过一遍源码,然后上流程图,最后我们再回头总结一 ...
- spring源码解析--事务篇(前篇)
对于每一个JAVA程序员,spring应该是再熟悉不过的框架了,它的功能有多强大我就不多说了,既然他有这么强大的功能,是如何实现的呢?这个就需要从他的原理去了解,而最直接了解原理的方式莫过于源码.当然 ...
- Spring源码解析 | 第一篇 :IntelliJ IDEA2019.3编译Spring5.3.x源码
前言 工欲善其事必先利其器.学习和深读Spring源码一个重要的前提:编译源码到我们的本地环境.这样方便我们在本地环境添加注释.断点追踪.查看类或接口的继承关系等等,更加高效的学习Spring源码.个 ...
- Spring源码之AbstractApplicationContext中refresh方法注释
https://blog.csdn.net/three_stand/article/details/80680004 refresh() prepareRefresh(beanFactory) 容器状 ...
- Spring源码 18 IOC refresh方法13
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码 16 IOC refresh方法11
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
随机推荐
- 前端浅谈---协议相关(TCP连接)
TCP连接 http的描述里面,我弱化了交互过程的描述,因为它相对复杂.所以我在此单独描述.客户端和服务端传递数据时过程相对谨慎和复杂,主要是开始和结束的过程.而这整个过程就是TCP连接.连接流程大体 ...
- MySQL慢日志优化
慢日志的性能问题 造成 I/O 和 CPU 资源消耗:慢日志通常会扫描大量非目的的数据,自然就会造成 I/O 和 CPU 的资源消耗,影响到其他业务的正常使用,有可能因为单个慢 SQL 就能拖慢整个数 ...
- [BUUCTF]PWN21——ciscn_2019_s_3
[BUUCTF]PWN21--ciscn_2019_s_3 附件 步骤 例行检查,64位,开启了NX保护 试运行的时候回显是一些乱码,直接用ida打开,从main函数开始看 main函数调用了vuln ...
- Docker从入门到精通(六)——容器通信
想要变成 Docker 的高阶玩家,搞懂 Docker 的容器通信是必不可少的. 1.需求 通常一个 Web 项目上线,我们会把开发完成的服务部署在Tomcat 服务器里面,然后需要的持久化数据会存放 ...
- 最新超详细VMware下CentOS系统安装
一.了解CentOS系统 CentOS是免费的.开源的.可以重新分发的开源操作系统,CentOS(Community Enterprise Operating System,中文意思是社区企业操作系统 ...
- 这样学习ZooKeeper离大厂所需技能要求还远吗
概述 定义 Apache ZooKeeper是一种用于构建分布式应用的高性能.高度可靠.开源的分布式协调服务,提供如配置信息维护.命名.分布式同步.组服务等功能,可以实现如分布式共识.组管理.领导选举 ...
- JS获取url中query_str JavaScript RegExp 正则表达式基础详谈
面我们举例一个URL,然后获得它的各个组成部分:http://i.cnblogs.com/EditPosts.aspx?opt=1 1.window.location.href(设置或获取整个 URL ...
- 7.2 Tornado异步
7.2 Tornado异步 因为epoll主要是用来解决网络IO的并发问题,所以Tornado的异步编程也主要体现在网络IO的异步上,即异步Web请求. 1. tornado.httpclient.A ...
- SDP 格式解析
一.SDP协议介绍 SDP 完全是一种会话描述格式 ― 它不属于传输协议 ― 它只使用不同的适当的传输协议,包括会话通知协议(SAP).会话初始协议(SIP).实时流协议(RTSP).MIME 扩展协 ...
- Centos7查看防火墙对应的开放端口以及进行端口操作
1.查看开放端口列表 [root@host bin]# firewall-cmd --list-ports 22/tcp 80/tcp 8888/tcp 39000-40000/tcp 12888/t ...