Spring 源码解读:IOC 原理之控制反转

阅读须知

  1. 买本 Spring 源码的书看!!!重要!!!重要!!!重要!!!
  2. Spring 源码阅读时,不要想着从头到尾把逻辑看懂,因为一块代码逻辑可能就设计非常多方面的内容,或者及其的复杂,学会取舍
  3. Spring 源码要想自己编译需要 Gradle 或者像我一样开一个普通的 Java 项目,利用那个项目去找代码文件位置
  4. 看源代码,一定勤做笔记

关于 IOC

IOC 流程大致分为三个步骤:

  1. 资源的定位,一般为 XML 读取
  2. IOC 的控制反转,此时还未正式去生成 IOC,只是准备好了随时可用的数据
  3. IOC 的依赖注入

我们以 XML 读取并进行依赖注入的过程为例,我会标明每个文件在哪个 Spring 项目下,以及对应的包路径,方便查找

找到 FileSystemXmlApplicationContext 对象,在传统 Web 中,项目通过这个读取 XML 里面的一些 Bean 配置,并对这些 Bean 进行依赖注入

spring-context:org.springframework.context.support.FileSystemXmlApplicationContext
在这里插入图片描述
这个 refresh() 方法会帮助我们完成 IOC 的载入,但在此之前我们需要看下资源是如何读取的。

XML 资源的定位

源码解读

我们先来看看 Spring 是如何实现控制反转的,也就是将构建 Bean 的权限交由 Srping 处理

既然要交给 Spring 处理,那么我们自然需要将 Bean 的信息整理好后交到 Spring 手上,然后它才会在需要的时候进行依赖注入

代码位置:spring-context:org.springframework.context.support.FileSystemXmlApplicationContext
在这里插入图片描述
refresh() 方法是 IOC 加载操作的入口


代码位置:spring-context:org.springframework.context.support.AbstractApplicationContext
在这里插入图片描述


代码位置:spring-context:org.springframework.context.support.AbstractApplicationContext
在这里插入图片描述
代码位置:spring-context:org.springframework.context.support.AbstractRefreshableApplicationContext
在这里插入图片描述
首先判断 Bean 是否已经存在,如果存在就销毁

之后需要通过 loadBeanDefinitions 来加载 BeanDefinition

PS:由于 XML 解析以及 BeanDefinition 的解析注入相对复杂,因此跳过,有需要可以对这一部分单独阅读,我们主要了解 IOC 的流程


既然要控制反转,那么自然首先要知道需要把哪些 Bean 交给 Spring 从而实现控制反转

因此首先我们要获取需要控制反转的资源

通过接口 loadBeanDefinitions 接口,我们可以找到我们所需要的实现类

代码位置:spring-context:org.springframework.context.support.AbstractXmlApplicationContext
在这里插入图片描述
先构建一个 XmlBeanDefinitionReader 加载器,后续的 XML 加载都是通过这个加载器实现的


代码位置:spring-context:org.springframework.context.support.AbstractXmlApplicationContext
在这里插入图片描述
循环加载 BeanDefinition,可以看到这里对应了两种的加载方式,一种是 Resource 方式,一种是 String 方式加载。

但是 String 方式其实就是多走了一步从 String 加载为 Resource 方式而已,我们直接来看 Resource 的加载


代码位置:spring-beans:org.springframework.beans.factory.support.AbstractBeanDefinitionReader

获取当前 Bean 的资源加载
逻辑应该很好理解,就是循环加载 Resource 中的资源


代码位置:spring-beans:org.springframework.beans.factory.xml.XmlBeanDefinitionReader
在这里插入图片描述


前面做了那么多事,其实都是只是在获取资源而已,根据需求不同走不同的实现来加载对应资源

接下来我们要开始 XML 文件的读取

XmlBeanDefinitionReader 通过继承 AbstractBeanDefinitionReader 完成了对 loadBeanDefinitions 的重写
代码位置:spring-beans:org.springframework.beans.factory.xml.XmlBeanDefinitionReader
在这里插入图片描述
可以看到,逻辑比较好理解,利用文件流读取文件,拿到 XML 内容,接下来进入 doLoadBeanDefinitions 方法要将 XML 转化为可用的 BeanDefinition


代码位置:spring-beans:org.springframework.beans.factory.xml.XmlBeanDefinitionReader
在这里插入图片描述
doLoadBeanDefinitions 主要就是把 XML 里面的内容读取为 Document 对象,接下来就要将 Document 转化为 BeanDefinition 能够使用的数据


代码位置:spring-beans:org.springframework.beans.factory.xml.XmlBeanDefinitionReader
在这里插入图片描述
先构建一个 BeanDefinitionDocumentReader 用来解析 Document,接下来开始解析 BeanDefinition,解析过程及其复杂


接下来简单引导下代码咋走的,至于具体的解析逻辑,并不是重点

这些解析主要是对 XML 标签进行一个个解析

代码位置:spring-beans:org.springframework.beans.factory.xml.XmlBeanDefinitionReader
在这里插入图片描述
代码位置:spring-beans:org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader
在这里插入图片描述
代码位置:spring-beans:org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader
在这里插入图片描述
代码位置:spring-beans:org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader
在这里插入图片描述
代码位置:spring-beans:org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader
在这里插入图片描述
代码位置:spring-beans:org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader
在这里插入图片描述
接下来的就是如何将 XML 解析的数据转换为 BeanDefinition 的数据了,到这里我们才完成了 XML 数据的读取

总结

XML 资源加载都干了什么?

  1. 利用 Resource 读取文件流到 Document
    PS:getResource() 会拿到 Resource 对象,再调用 getInputStream() 读取
  2. BeanDefinitionDocumentReader 把 Document 解析成 BeanDefinition

IOC 的控制反转

源码解读

从上面的接口继续往下走
代码位置:spring-beans:org.springframework.beans.factory.support.BeanDefinitionReaderUtils
在这里插入图片描述

通过这个接口,我们正式进入 BeanDefinition 注册的流程


我们进入实现类 DefaultListableBeanFactory

BeanDefinition 向 IOC 容器中注册的逻辑并不复杂,整体上就是把 BeanDefinition 设置到 HashMap 中

代码位置:spring-beans:org.springframework.beans.factory.support.DefaultListableBeanFactory
在这里插入图片描述
代码比较长,注册前进行最后一次的校验
在这里插入图片描述
接下来会进行一次同名 Bean 的验证,如果同名但是不让覆盖就会抛出异常,这也是很常见的异常
在这里插入图片描述
下面我们正式进入注册部分,逻辑很简单

由于要保证线程安全性,因此用 synchronized 包裹起来

然后将 BeanDefinition 设置到 beanDefinitionMap 这个 IOC 容器里(到此已实现控制反转)

接下来把 Bean 的名字设置到 BeanDefinitionNames 中应该是用来做校验之类的

总结

IOC 的控制反转:

  1. 通过 BeanDefinitionRegistery 将 BeanDefinition 注册进 IOC

结尾

Spring 源码解读:IOC 原理之依赖注入

Spring 源码阅读-注释版

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值