| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> Spring是如何解决循坏依赖的? -> 正文阅读 |
|
[Java知识库]Spring是如何解决循坏依赖的? |
我们先来看getBean这个方法,因为这个方法里面实现了一个Bean实例化到初始化最终变成一个完整的bean的过程 org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean?
?其中doGetBean里面一开始有一段这样的代码,逻辑也很简单,就是从getSingleton方法中尝试获取bean,如果获取到了就直接返回这个bean了 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String) org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
?在这里我们先对这段代码有一点印象,之后再来看这段代码 ? org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory) org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#beforeSingletonCreation 继续回到doGetBean方法,该方法正常流程会走到
?在getSingleton方法中首先会从单例对象池中判断是否已经有这个bean了,如果没有就会走下一步,而这个下一步里面会调用到父类的一个beforeSingletonCreation方法,在这个方法中会把当前的beanName放入到singletonsCurrentlyInCreation这个集合中,而这个集合里面存放的是当前正在创建的beanName,这个存放当前正在创建的beanName的集合对于解决循环依赖来说很重要,而为什么在这里才把这个bean放到这个集合中?我猜想是因为当spring实例化一个bean的时候走到这一步,确定了当前容器没有这个bean了,就会从这里开始标识我要开始创建bean了,就会把这个bean存入这个集合当中。在确定了这个bean需要创建的时候,就会调用到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[]) org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean doGetBean就是包含了spring实例化初始化bean过程的实现方法了,这其中在bean实例化之后,属性注入之前,有一段很重要的代码
?在这一段代码中首先会判断这个bean是否符合循环依赖的条件,条件为这个bean必须是单例的,而且allowCircularReferences属性必须为true(这个属性可以通过外部api进行配置),以及这个bean是否是正在创建的,如果这些条件都符合的话,就会调用到addSingletonFactory方法 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory?
这里说一下上面的bean工厂,这个bean工厂spring传入的是一段lambda表达式,具体调用这个bean工厂的getObject方法的时候,会调用到getEarlyBeanReference方法,这个方法中其实是能够得到一个bean的最终状态。好了,说了这么多,我们就需要把上面的东西都串起来,又以A和B为例子,假如上面getBean的流程是对A进行了,也就是getBean(A),那么此时当它走完上面的代码就会来到属性注入的逻辑了,也就是populateBean方法,往A里面注入B,当注入B的时候就会发现B依赖了A,那么如果不解决循坏依赖的问题就会产生一个死循坏了,当前的循坏如下面所示:
而spring怎么解决这个死循坏的呢,就是通过上面的东西了,接下来重点看一下B注入A的时候调用getBean(A)的过程。重新来到getBean的代码,上面说过了B的getBean(A)会经过getSingleton的方法尝试去容器里面拿A ? getBean(A)->实例化A->属性注入B->getBean(B)->实例化B->属性注入A->getBean(A)->getSingleton(A)->三级缓存或者二级缓存中得到A->B得到A并注入->B走完剩下的生命周期->把B放入一级缓存->回到A的属性注入生命周期,此时得到B了并注入->A走完剩下的声明周期->把A放到一级缓存 ?所以说在B注入A然后调用getBean(A)的时候,在getSingleton就能拿到A了,此时B的属性注入完成,直到B的生命周期结束,然后回到A的属性注入生命周期,最后A的生命周期结束,最终循坏依赖解决,流程如下:
在这个过程中,可以发现,解决循坏依赖的关键点在于,记录了A是否是正在创建的,并且在A属性注入之前会提前暴露了A的工厂,在A注入B然后B去注入A调用getBean(A)的时候就能够拿到A之前提前暴露的工厂,从这个工厂中拿到A? 二级缓存的意义?前面说了这个二级缓存就是存放一个bean的工厂的,这个bean工厂的作用就是生产这个bean,那么在A属性注入之前我们直接暴露A不就好了吗,反正此时A已经被实例化了,何必大费周章地去搞一个A的工厂呢?也就是说是否可以直接把实例化好的A放入到三级缓存中就好了,并不需要二级缓存?如果是普通的一个bean的话二级缓存确实是没必要的,但是我们需要考虑的一种场景就是代理
可以看到如果是直接把A放入到三级缓存,然后B从三级缓存中去拿到A并注入,当A完整地走完自己的生命周期的时候你会发现此时的A已经是变成一个代理对象了,而B依赖的那个A却还只是一个普通对象,而引入二级缓存就能够解决这个问题,因为二级缓存中放的是A的工厂,而既然是工厂,那么就能产生出A的代理对象了,也就是上面一直说的A的最终形态,因为在A还没走完自己的生命周期的时候,A这个对象是有可能变的,所以我们不能够直接暴露出这个A实例,而是需要暴露出A的工厂,从这个工厂才能拿到A的最终形态!?
三级缓存的意义??既然上面说了二级缓存存的是bean的工厂,而且这个工厂这么牛逼能够产生bean的最终形态,那干嘛还用三级缓存?直接从工厂里面拿这个最终形态不就好了吗?我们看下spring是怎么做的
spring每一次都是从一个三级缓存中拿bean,如果为空就从二级缓存中的bean工厂产生bean并且放到三级缓存中,这样做的目的就是减少性能的消耗,因为假如A依赖了100个对象,而这个100个对象又依赖了A,那么这100个对象每一次从工厂中拿一个最终形态的A都是一个极其复杂的过程,所以既然这个A也已经是个最终形态的A了,那么就能够直接缓存起来,下次需要用的需要直接从三级缓存拿就可以了? ? |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 9:34:52- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |