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

上篇文章对spring核心启动方法refresh做了整体的解读,但是只是泛泛而谈,接下来会出一系统文章对每个方法的源码进行深刻解读。

第一篇文章见 spring源码之方法概览

首先,第一个方法是prepareRefresh()方法,这个方法做的事很简单,也不是本文的重点。该方法记录容器的启动时间,初始化监听容器。

  1. protected void prepareRefresh() {
  2. // Switch to active
  3. //纪录启动时间
  4. this.startupDate = System.currentTimeMillis();
  5. System.out.println("spring启动时间为--------------------" + this.startupDate);
  6. this.closed.set(false);
  7. System.out.println("spring标记为未关闭--------------------" + this.closed);
  8. this.active.set(true);
  9. System.out.println("spring当前激活状态--------------------" + this.active);
  10. if (logger.isDebugEnabled()) {
  11. if (logger.isTraceEnabled()) {
  12. logger.trace("Refreshing " + this);
  13. } else {
  14. logger.debug("Refreshing " + getDisplayName());
  15. }
  16. }
  17. // Initialize any placeholder property sources in the context environment.
  18. //空方法
  19. initPropertySources();
  20. // Validate that all properties marked as required are resolvable:
  21. // see ConfigurablePropertyResolver#setRequiredProperties
  22. //校验 xml配置文件
  23. getEnvironment().validateRequiredProperties();
  24. // Store pre-refresh ApplicationListeners...
  25. //初始化applicationListeners监听容器
  26. if (this.earlyApplicationListeners == null) {
  27. this.earlyApplicationListeners = new LinkedHashSet<> (this.applicationListeners);
  28. } else {
  29. // Reset local application listeners to pre-refresh state.
  30. this.applicationListeners.clear();
  31. this.applicationListeners.addAll(this.earlyApplicationListeners);
  32. }
  33. // Allow for the collection of early ApplicationEvents,
  34. // to be published once the multicaster is available...
  35. this.earlyApplicationEvents = new LinkedHashSet<>();
  36. }

读者大致搂一眼即可,对这个方法整体就能很快把握。

接下来才是今天的重头戏——obtainFreshBeanFactory()方法,是refresh()方法中的第二个方法,也是整个refresh()方法中核心方法之一。

该方法主要的作用是,这里将会初始化 BeanFactory、加载 Bean、注册 Bean 等等。(Bean 并没有完成初始化)

点进去obtainFreshBeanFactory()方法我们一探究竟。

  1. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  2. // 关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean 等等
  3. refreshBeanFactory();
  4. // 返回刚刚创建的 BeanFactory
  5. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  6. if (logger.isDebugEnabled()) {
  7. logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
  8. }
  9. return beanFactory;
  10. }

refreshBeanFactory()应该是这个方法的重头戏,我们再深入进去。

  1. @Override
  2. protected final void refreshBeanFactory() throws BeansException {
  3. // 如果 ApplicationContext 中已经加载过 BeanFactory 了,销毁所有 Bean,关闭 BeanFactory
  4. // 注意,应用中 BeanFactory 本来就是可以多个的,这里可不是说应用全局是否有 BeanFactory,而是当前ApplicationContext 是否有 BeanFactory
  5. if (hasBeanFactory()) {
  6. destroyBeans();
  7. closeBeanFactory();
  8. }
  9. try {
  10. // 初始化一个 DefaultListableBeanFactory,为什么使用这个BeanFactory?因为这是最牛的 BeanFactory。
  11. DefaultListableBeanFactory beanFactory = createBeanFactory();
  12. // 用于 BeanFactory 的序列化
  13. beanFactory.setSerializationId(getId());
  14. // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
  15. customizeBeanFactory(beanFactory);
  16. // 加载 Bean 到 BeanFactory 中
  17. loadBeanDefinitions(beanFactory);
  18. synchronized (this.beanFactoryMonitor) {
  19. this.beanFactory = beanFactory;
  20. }
  21. }
  22. catch (IOException ex) {
  23. throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
  24. }
  25. }

简单提一句,DefaultListableBeanFactory为什么是最牛的BeanFactory看下这个继承图大概就明了。

  1. // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
  2. customizeBeanFactory(beanFactory);

这个方式只是一个设置,设置是否允许循环依赖,至于什么是循环依赖呢?也就是 A-B-C之间他们相互依赖,spring有一套自己的机制去处理循环依赖,以后文章为进行分析,这一步仅仅是配置是否允许循环依赖,读者清楚就可以了。

  1. // 这个方法将根据配置,加载各个 Bean,然后放到 BeanFactory 中
  2. 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. 代码图形统计工具git_stats web

    目录 一.简介 二.安装ruby 三.配置git_stats 四.通过nginx把网页展示出来 一.简介 仓库代码统计工具之一,可以按git提交人.提交次数.修改文件数.代码行数.注释量在时间维度上进 ...

  2. 发布iOS应用(xcode5)到App Store(苹果商店) 详细解析

    发布iOS应用(xcode5)到App Store(苹果商店) 详细解析 作者:Memory 发布于:2014-8-8 10:44 Friday IOS 此教程可能不太适合,请移步至最新最全的:201 ...

  3. [BUUCTF]REVERSE——[BJDCTF2020]easy

    [BJDCTF2020]easy 附件 例行检查,无壳,32位程序 32位ida载入,main函数和字符串理都没有找到有关flag的提示 根据main函数的提示,有关flag的函数应该被藏起来了,在左 ...

  4. tomcat架构分析及配置详解

    浏览器访问服务器的流程 请求发起的过程: 注意:浏览器访问服务器使用的是http协议,http是应用层协议,而具体传输还是使用的TCP/IP协议 Tomcat系统总架构 2.1 Tomcat请求处理过 ...

  5. 工厂为什么要进行计划排产,APS高级计划排程系统的优势作用是什么?

    我们每个人的指挥中心是大脑,大脑对我们身体发出各种各样的指令,不停的告诉我们身体去干什么. 那么,一个制造企业的指挥中心是哪里?工厂每天都会接到各种各样的订单,通过几百上千的工人,使用各种设备来生产. ...

  6. 摘要任务工期计算(Project)

    <Project2016 企业项目管理实践>张会斌 董方好 编著 先说一个好消息:摘要工期是可以自动计算的. 比如A1.A2.A3.A4四个任务,工期如下图安排: 而他们的摘要任务,就不再 ...

  7. CF508A Pasha and Pixels 题解

    Content 有一个 \(n\times m\) 的矩阵,一开始全部格子被染成白色. 接下来有 \(k\) 个操作,每一个操作表示把一个格子染成黑色.问第一次出现 \(2\times 2\) 的全部 ...

  8. docker部署验证码项目报错:at sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)

    如果docker部署启动报错 java.lang.NullPointerException: nullat sun.awt.FontConfiguration.getVersion(FontConfi ...

  9. 【LeetCode】1222. Queens That Can Attack the King 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 遍历 日期 题目地址:https://leetcode ...

  10. [Xavier] Understanding the difficulty of training deep feedforward neural networks

    目录 概 主要内容 Glorot X, Bengio Y. Understanding the difficulty of training deep feedforward neural netwo ...