大家好,我是程序员田同学

上篇文章对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第二篇的更多相关文章

  1. 【Spring源码分析】预备篇

    前言 最新想学习一下Spring源码,开篇博客记录下学习过程,欢迎一块交流学习. 作为预备篇,主要演示搭建一个最简单的Spring项目样例,对Spring进行最基本梳理. 构建一个最简单的spring ...

  2. Spring源码解析 | 第二篇:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  3. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  4. java架构之路-(spring源码篇)springIOC容器源码解析(上)

    我们这次来叭叭一下Spring的源码,这次博客主要来说说Spring源码,先粗略的撸一遍,下篇博客选几个重点去说,由于过于复杂,我也是看了一点点,我们先来过一遍源码,然后上流程图,最后我们再回头总结一 ...

  5. spring源码解析--事务篇(前篇)

    对于每一个JAVA程序员,spring应该是再熟悉不过的框架了,它的功能有多强大我就不多说了,既然他有这么强大的功能,是如何实现的呢?这个就需要从他的原理去了解,而最直接了解原理的方式莫过于源码.当然 ...

  6. Spring源码解析 | 第一篇 :IntelliJ IDEA2019.3编译Spring5.3.x源码

    前言 工欲善其事必先利其器.学习和深读Spring源码一个重要的前提:编译源码到我们的本地环境.这样方便我们在本地环境添加注释.断点追踪.查看类或接口的继承关系等等,更加高效的学习Spring源码.个 ...

  7. Spring源码之AbstractApplicationContext中refresh方法注释

    https://blog.csdn.net/three_stand/article/details/80680004 refresh() prepareRefresh(beanFactory) 容器状 ...

  8. Spring源码 18 IOC refresh方法13

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  9. Spring源码 16 IOC refresh方法11

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

随机推荐

  1. 前端浅谈---协议相关(TCP连接)

    TCP连接 http的描述里面,我弱化了交互过程的描述,因为它相对复杂.所以我在此单独描述.客户端和服务端传递数据时过程相对谨慎和复杂,主要是开始和结束的过程.而这整个过程就是TCP连接.连接流程大体 ...

  2. MySQL慢日志优化

    慢日志的性能问题 造成 I/O 和 CPU 资源消耗:慢日志通常会扫描大量非目的的数据,自然就会造成 I/O 和 CPU 的资源消耗,影响到其他业务的正常使用,有可能因为单个慢 SQL 就能拖慢整个数 ...

  3. [BUUCTF]PWN21——ciscn_2019_s_3

    [BUUCTF]PWN21--ciscn_2019_s_3 附件 步骤 例行检查,64位,开启了NX保护 试运行的时候回显是一些乱码,直接用ida打开,从main函数开始看 main函数调用了vuln ...

  4. Docker从入门到精通(六)——容器通信

    想要变成 Docker 的高阶玩家,搞懂 Docker 的容器通信是必不可少的. 1.需求 通常一个 Web 项目上线,我们会把开发完成的服务部署在Tomcat 服务器里面,然后需要的持久化数据会存放 ...

  5. 最新超详细VMware下CentOS系统安装

    一.了解CentOS系统 CentOS是免费的.开源的.可以重新分发的开源操作系统,CentOS(Community Enterprise Operating System,中文意思是社区企业操作系统 ...

  6. 这样学习ZooKeeper离大厂所需技能要求还远吗

    概述 定义 Apache ZooKeeper是一种用于构建分布式应用的高性能.高度可靠.开源的分布式协调服务,提供如配置信息维护.命名.分布式同步.组服务等功能,可以实现如分布式共识.组管理.领导选举 ...

  7. JS获取url中query_str JavaScript RegExp 正则表达式基础详谈

    面我们举例一个URL,然后获得它的各个组成部分:http://i.cnblogs.com/EditPosts.aspx?opt=1 1.window.location.href(设置或获取整个 URL ...

  8. 7.2 Tornado异步

    7.2 Tornado异步 因为epoll主要是用来解决网络IO的并发问题,所以Tornado的异步编程也主要体现在网络IO的异步上,即异步Web请求. 1. tornado.httpclient.A ...

  9. SDP 格式解析

    一.SDP协议介绍 SDP 完全是一种会话描述格式 ― 它不属于传输协议 ― 它只使用不同的适当的传输协议,包括会话通知协议(SAP).会话初始协议(SIP).实时流协议(RTSP).MIME 扩展协 ...

  10. Centos7查看防火墙对应的开放端口以及进行端口操作

    1.查看开放端口列表 [root@host bin]# firewall-cmd --list-ports 22/tcp 80/tcp 8888/tcp 39000-40000/tcp 12888/t ...