Spring 源码阅读 04:BeanFactory 初始化

简介: 本篇要阅读的是 BeanFactory 初始化的部分,也就是 AbstractApplicationContext#refresh 方法中的 obtainFreshBeanFactory() 方法调用.

基于 Spring Framework v5.2.6.RELEASE

接前文:Spring 源码阅读:初始化 Spring 上下文信息

在之前的 ApplicationContext 初始化 Spring 容器 一文中,我们提到了 AbstractApplicationContext#refresh 方法是一个非常重要的方法,它包含了 Spring 容器初始化的整个流程,我们将对这里的源码进行细致地阅读。本篇要阅读的是 BeanFactory 初始化的部分,也就是 refresh 方法中的这一行方法调用:

// Tell the subclass to refresh the internal bean factory.// 这里会调用模版方法,通过子类的实现,初始化 BeanFactory 并解析 XML 配置ConfigurableListableBeanFactorybeanFactory=obtainFreshBeanFactory();

这里调用了 obtainFreshBeanFactory 并得到了一个 ConfigurableListableBeanFactory 类型的 beanFactory。这个方法的作用是初始化 beanFactory ,还会解析 XML 中配置的 Bean。

我们先看源码:

/*** Tell the subclass to refresh the internal bean factory.* @return the fresh BeanFactory instance* @see #refreshBeanFactory()* @see #getBeanFactory()*/protectedConfigurableListableBeanFactoryobtainFreshBeanFactory() {
refreshBeanFactory();
returngetBeanFactory();
}

这个方法的源码很简单,调用了两个方法,并将第二个方法的结果返回。根据方法的名称可以看到,第一个方法用来刷新(或者初始化)beanFactory,第二个方法用来获取 beanFactory 并返回。

refreshBeanFactory 方法

我们先看 refreshBeanFactory 方法,具体实现过程可以在 AbstractRefreshableApplicationContext 类找到 :

/*** This implementation performs an actual refresh of this context's underlying* bean factory, shutting down the previous bean factory (if any) and* initializing a fresh bean factory for the next phase of the context's lifecycle.*/@OverrideprotectedfinalvoidrefreshBeanFactory() throwsBeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
   }
try {
DefaultListableBeanFactorybeanFactory=createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory=beanFactory;
      }
   }
catch (IOExceptionex) {
thrownewApplicationContextException("I/O error parsing bean definition source for "+getDisplayName(), ex);
   }
}

从方法的整体流程可以看出,不管当前是不是存在一个 BeanFactory ,这里都会创建一个新的,并进行初始化,我们来逐行分析代码。

销毁已有的 BeanFactory

一开始,会判断当前是否存在一个 BeanFactory,如果有的话,就销毁其中的 Bean,并关闭 BeanFactory。这部分逻辑对应方法体开头的 if 语句块。因为我们分析的是 Spring 容器第一次创建时候的流程,而且之前并没有 BeanFactory 创建的逻辑,所以,目前为止,并不存在一个 BeanFactory,if 语句中的逻辑不会被执行。

实例化新的 BeanFactory

接下来就是 try 语句块中的部分。

首先,执行了 createBeanFactory 方法,创建了一个 BeanFactory。这里的代码也很简单:

protectedDefaultListableBeanFactorycreateBeanFactory() {
returnnewDefaultListableBeanFactory(getInternalParentBeanFactory());
}

获取到 parent 后,调用构造方法,创建了一个 DefaultListableBeanFactory 的实例并返回。

这里的构造方法中还有一些步骤,与本文的主线内容关系不大,暂时先挖个坑,坑填之后会将链接贴在这里

Spring 源码阅读 05:忽略感知接口对应成员变量的自动装配

DefaultListableBeanFactory 这个类型是第一次见到,我们可以大致看一下它的继承关系:

image.png

这里的接口实现关系错综复杂,可以先看看留个印象。值得一提的是,它的子类 XmlBeanFactory 是 Spring 中非常重要的一个类,是 Spring 的初级容器。如果使用 XML 配置文件来直接创建 BeanFactory 使用的就是 XmlBeanFactory ,不过现在这个类已经被标记了 @Deprecated

言归正传,回到 refreshBeanFactory 方法中来。创建好 BeanFactory 后,通过 beanFactory.setSerializationId(getId()) 给了它一个 Id,序列化和反序列化的时候用。

对 BeanFactory 进行自定义

接下来,customizeBeanFactory(beanFactory) 执行了 ApplicationContext 对内部的 BeanFactory 的自定义。

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
   if (this.allowBeanDefinitionOverriding != null) {
      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
   if (this.allowCircularReferences != null) {
      beanFactory.setAllowCircularReferences(this.allowCircularReferences);
   }
}

这里通过给 beanFactory 的成员变量赋值,做了两件事:

  • 允许相同名称的 BeanDefinition 在容器中被覆盖
  • 允许多个 Bean 之间存在循环依赖

这两点涉及到了 BeanDefinition 和 Bean 初始化的流程,根据容器初始化的整体流程(可以参考:Spring 源码阅读:ApplicationContext 初始化 Spring 容器 ),在之后的代码中应该会遇到。

加载 BeanDefinition

最后一个方法调用,loadBeanDefinitions(beanFactory); 执行了 BeanDefinition 的加载。这里的实现逻辑可以在 AbstractXmlApplicationContext 中找到:

/*** Loads the bean definitions via an XmlBeanDefinitionReader.* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader* @see #initBeanDefinitionReader* @see #loadBeanDefinitions*/@OverrideprotectedvoidloadBeanDefinitions(DefaultListableBeanFactorybeanFactory) throwsBeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.XmlBeanDefinitionReaderbeanDefinitionReader=newXmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(newResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}

在这个方法中,首先创建了一个 XmlBeanDefinitionReader 的实例,并对其进行了配置。从它的名字可以知道,这个类用来读取 XML 中的 Bean 定义。

创建好之后,末尾调用了两个方法,我们先看 initBeanDefinitionReader 的源码:

protectedvoidinitBeanDefinitionReader(XmlBeanDefinitionReaderreader) {
reader.setValidating(this.validating);
}

方法名告诉我们方法的作用是对 XmlBeanDefinitionReader 进行初始化,这里只是设置了是否对 XML 文件进行验证(默认值是 true),其余什么也没干。我们还注意到,这个方法是 protected 修饰的,因此可以断定,这里是 Spring 留给我们的一个扩展点。我们可以通过重写这个方法,关闭 XML 验证、自定义 XML 的解析器,或者执行其他的一些设置。

最后将 beanDefinitionReader 作为参数,调用了另外一个 loadBeanDefinitions 方法。源码如下:

protectedvoidloadBeanDefinitions(XmlBeanDefinitionReaderreader) throwsBeansException, IOException {
Resource[] configResources=getConfigResources();
if (configResources!=null) {
reader.loadBeanDefinitions(configResources);
   }
String[] configLocations=getConfigLocations();
if (configLocations!=null) {
reader.loadBeanDefinitions(configLocations);
   }
}

在这里,分别将 configResourcesconfigLocations 作为参数,执行了 readerloadBeanDefinitions 方法。不过,getConfigResources 这个方法直接返回了 null,因此,这里的逻辑就是,根据我们创建 ClassPathXmlApplicationContext 时提供的配置文件路径,进行 BeanDefinition 的加载。

这里 reader.loadBeanDefinitions 方法加载 BeanDefinition 的逻辑是现在 AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String...) 方法中,这里面还有很多流程,我打算放到另外一篇文章中,这里又挖了一个坑,填坑后我会将链接更新到这里。

Spring 源码阅读 06:加载 BeanDefinition 的过程(准备阶段)

Spring 源码阅读 07:加载 BeanDefinition 的过程(资源加载阶段)

Spring 源码阅读 08:加载 BeanDefinition 的过程(解析阶段)

Spring 源码阅读 09:加载 BeanDefinition 的过程(注册阶段)

完成初始化并赋值

方法的末尾,通过 this.beanFactory = beanFactory; 将之前创建并初始化好的 BeanFactory 赋值给 beanFactory 成员变量。

getBeanFactory 方法

最后我们在回到最开始的 obtainFreshBeanFactory 方法,看一下里面调用的第二个方法 getBeanFactory() 的源码,实现逻辑在 AbstractRefreshableApplicationContext 类中:

@OverridepublicfinalConfigurableListableBeanFactorygetBeanFactory() {
synchronized (this.beanFactoryMonitor) {
if (this.beanFactory==null) {
thrownewIllegalStateException("BeanFactory not initialized or already closed - "+"call 'refresh' before accessing beans via the ApplicationContext");
      }
returnthis.beanFactory;
   }
}

这里其实就是把 refreshBeanFactory 方法创建并初始化的 BeanFactory 获取到并返回。

目录
相关文章
|
6天前
|
监控 Java 应用服务中间件
Spring Boot 源码面试知识点
【5月更文挑战第12天】Spring Boot 是一个强大且广泛使用的框架,旨在简化 Spring 应用程序的开发过程。深入了解 Spring Boot 的源码,有助于开发者更好地使用和定制这个框架。以下是一些关键的知识点:
25 6
|
6天前
|
Java 应用服务中间件 测试技术
深入探索Spring Boot Web应用源码及实战应用
【5月更文挑战第11天】本文将详细解析Spring Boot Web应用的源码架构,并通过一个实际案例,展示如何构建一个基于Spring Boot的Web应用。本文旨在帮助读者更好地理解Spring Boot的内部工作机制,以及如何利用这些机制优化自己的Web应用开发。
32 3
|
6天前
|
存储 前端开发 Java
Spring Boot自动装配的源码学习
【4月更文挑战第8天】Spring Boot自动装配是其核心机制之一,其设计目标是在应用程序启动时,自动配置所需的各种组件,使得应用程序的开发和部署变得更加简单和高效。下面是关于Spring Boot自动装配的源码学习知识点及实战。
17 1
|
6天前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
108 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
|
6天前
|
设计模式 安全 Java
【初学者慎入】Spring源码中的16种设计模式实现
以上是威哥给大家整理了16种常见的设计模式在 Spring 源码中的运用,学习 Spring 源码成为了 Java 程序员的标配,你还知道Spring 中哪些源码中运用了设计模式,欢迎留言与威哥交流。
|
6天前
|
消息中间件 安全 Java
探索|Spring并行初始化加速的思路和实践
作者通过看过的两篇文章发现实现Spring初始化加速的思路和方案有很多类似之处,通过本文记录一下当时的思考和实践。
|
6天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
9月前
|
Java Spring 容器
Spring中BeanFactory和FactoryBean的区别?
一位工作了4年的小伙伴,去京东面试被问到这样一个问题,Spring中的BeanFactory和FactoryBean有什么区别?因为没有看过源码,当时就感觉这是一个文字游戏,感觉没什么区别? 那今天,我就给大家来聊清楚。另外,往期面试题解析中配套的文档我已经准备好,想获得的可以在我的煮叶简介中找到。好了,我们先来看BeanFactory。
34 0
|
6天前
|
XML Java 数据格式
Spring5源码(8)-BeanFactory和FactoryBean的区别
Spring5源码(8)-BeanFactory和FactoryBean的区别
34 0
|
6月前
|
XML Java 数据格式
Spring中BeanFactory和FactoryBean详解
Spring中BeanFactory和FactoryBean详解
76 1