当前位置: 首页 > news >正文

国内大的网站建设公司排名竞价排名的服务模式是

国内大的网站建设公司排名,竞价排名的服务模式是,如何做中英切换的网站,西宁建网站需要多少钱人人都能看懂的Spring源码解析,Spring如何解决循环依赖原理解析什么是循环依赖循环依赖会有什么问题?如何解决循环依赖问题的根本原因如何解决为什么需要三级缓存?Spring的三级缓存源码走读Spring的三级缓存提前暴露getSingleton方法总结往期…

人人都能看懂的Spring源码解析,Spring如何解决循环依赖

  • 原理解析
    • 什么是循环依赖
    • 循环依赖会有什么问题?
    • 如何解决循环依赖
      • 问题的根本原因
      • 如何解决
    • 为什么需要三级缓存?
    • Spring的三级缓存
  • 源码走读
    • Spring的三级缓存
    • 提前暴露
    • getSingleton方法
  • 总结

往期内容:

  1. 人人都能看懂的Spring底层原理,看完绝对不会懵逼
  2. 简单易懂的Spring扩展点详细解析,看不懂你来打我
  3. 人人都能看懂的Spring源码解析,配置解析与BeanDefinition加载注册
  4. 简单易懂又非常牛逼的Spring源码解析,ConfigurationClassPostProcessor的具体逻辑
  5. 简单易懂值得收藏的Spring源码解析,依赖注入和bean的初始化

原理解析

什么是循环依赖

两个Bean,BeanA和BeanB,它们都有一个引用指向对方,这就是最简单的循环依赖。还有更复杂的循环依赖,涉及到多个bean,只要其中形成环,就是循环依赖。

在这里插入图片描述

循环依赖会有什么问题?

如果Spring不对这种情况做处理,那么在进行依赖注入的时候就会出现死循环

在这里插入图片描述

如何解决循环依赖

问题的根本原因

要解决循环依赖的问题,首先就要分析导致这个问题的根本原因。

因为上面是假设Spring只有一个缓存,那就是单例缓存池,而且该缓存池是用于存放已初始化完成的bean,而没有完成依赖注入的bean不算是初始化完成的bean,所以不会放入单例缓存池中。

所以beanA依赖beanB时,只能实例化一个beanB,然后对其进行依赖注入,而beanB又依赖了beanA,所以又只能实例化一个beanA,对其进行依赖注入,这样就没完没了了。

如何解决

解决办法就是多增加一个缓存(二级缓存),用于存放已经实例化但是未完成初始化的bean。因为增加了一个二级缓存,在bean被实例化的之后就预先放入到该二级缓存中,那么在后续其他bean进行依赖注入的时候,发现依赖了该bean,然后检查到二级缓存中有,就不需要往下进行实例化。

在这里插入图片描述

比如上图,在第二次getBean(beanA)的时候,二级缓存中已经存放了beanA,因此不会往下再次进行beanA的实例化,而是直接从缓存中取,死循环因此就解决了。

为什么需要三级缓存?

那看起来搞两级缓存就能解决问题,但是Spring实际上是有三级缓存的,那为什么Spring需要搞三级缓存呢

那是因为Spring要处理AOP,我们可以想一想,如果只有两级缓存,要怎么同时处理循环依赖和AOP呢?

此时就要在每个bean实例化后,放入二级缓存之前,都要判断一下这个bean是否需要进行AOP处理:如果需要,就要先通过动态代理生成代理对象,放入二级缓存的就是代理对象;如果不需要进行AOP处理,那么就把原始对象放入二级缓存。

这个显然不符合Spring的设计。Spring的设计是把AOP放到依赖注入完成以后,在初始化阶段触发的,而现在却要把AOP的处理提前到实例化之后。

那如果还是要把AOP放到初始化阶段触发,只有涉及到循环依赖的bean才提前进行AOP呢?那就要在每次从二级缓存获取bean的时候,都要判断一下是否需要进行AOP处理,这样就太繁琐了。

因此最好的解决办法就是再加一级缓存,三级缓存。先从二级缓存中取,如果有,直接返回,如果二级缓存没有,再从三级缓存中拿,放入二级缓存,并从三级缓存删除,并且只有从三级缓存中取的时候,才判断是否需要进行AOP处理

在这里插入图片描述

Spring的三级缓存

在这里插入图片描述

  • singletonObjects:一级缓存,Map<String, Object>类型,key是beanName,value是已初始化完成的bean。
  • earlySingletonObjects:二级缓存,Map<String, Object>类型,key是beanName,value是已实例化完成但是未进行初始化的bean。
  • singletonFactories:三级缓存,Map<String, ObjectFactory<?>>,key是beanName,value是ObjectFactory<?>类型。ObjectFactory是一个函数式接口,可以视为一个回调函数,里面的逻辑就是调用bean后置处理判断是否需要进行AOP处理,如果需要则进行AOP处理,返回一个代理对象,如果不需要进行AOP处理,则返回原始对象。

源码走读

Spring的三级缓存

在这里插入图片描述

上面描述的三级缓存,就是DefaultSingletonBeanRegistry的成员变量

在这里插入图片描述

DefaultSingletonBeanRegistry又是DefaultListableBeanFactory的祖先类,所以三级缓存就在DefaultListableBeanFactory里面。

提前暴露

在这里插入图片描述
AbstractAutowireCapableBeanFactory#doCreateBean方法,首先调用createBeanInstance方法进行bean的实例化

在这里插入图片描述
实例化以后,就是判断是否需要提前暴露(earlySingletonExposure为true),如果需要,则调用addSingletonFactory方法进行提前暴露

然后下面的populateBean方法里面就是依赖注入的处理,initializeBean方法里面就是bean初始化的处理,这两个方法在前面的文章已经讲过。

需要提前暴露的条件:

  • mbd.isSingleton():是否单例。
  • this.allowCircularReferences:是否允许循环依赖,默认为true(但是高版本改成默认为false了,Spring希望我们把代码写的更好,而不是指望Spring来给我们处理循环依赖的问题)。
  • isSingletonCurrentlyInCreation(beanName):该bean是否正在创建中。

三个条件都满足,就调用addSingletonFactory方法,提前暴露。

在这里插入图片描述
addSingletonFactory方法里面,就是把beanName和ObjectFactory类型的对象singletonFactory,放入三级缓存singletonFactories。这里的singletonFactory的就是外面的lambda表达式 () -> getEarlyBeanReference(beanName, mbd, bean)。ObjectFactory是一个函数式接口,里面有一个getObject方法,而singletonFactory的getObject方法就是调用getEarlyBeanReference(beanName, mbd, bean)。

getSingleton方法

一个bean在依赖注入阶段,要处理对别的bean的依赖,会调用beanFactory的getBean方法,尝试从容器中取,getBean方法会先调用getSingleton方法,尝试从三级缓存中取

在这里插入图片描述

  1. 首先从第一级缓存取this.singletonObjects.get(beanName),不是null就返回
  2. 如果第一级缓存取到的是null,则从第二级缓存取this.earlySingletonObjects.get(beanName),不是null就返回
  3. 如果第二级缓存取到的还是null,则从第三级缓存取this.singletonFactories.get(beanName)
  4. 如果第三级缓存取到的不是null,则调用getObject方法,获取getObject方法返回的对象,放入二级缓存,从三级缓存中删除
  5. 如果第三级缓存取到的还是null,就要走创建bean的逻辑

这里的singletonFactory的getObject实现方法,就是addSingletonFactory方法的第二个参数的lambda表达式 () -> getEarlyBeanReference(beanName, mbd, bean),也就是会调用 getEarlyBeanReference(beanName, mbd, bean) 方法获取返回的对象。
在这里插入图片描述

可以看到遍历所有的bean后置处理器,判断如果是SmartInstantiationAwareBeanPostProcessor类型,就回调getEarlyBeanReference方法,这里会进入到AbstractAutoProxyCreator#getEarlyBeanReference方法。

在这里插入图片描述
wrapIfNecessary方法就是判断如果当前bean需要进行AOP处理,则进行动态代理,返回代理对象;如果不需要进行AOP处理,会返回原始对象。

总结

以上就是关于“Spring如何处理循环依赖”的讲解的全部内容。下面做一个简单总结:

  • Spring是通过三级缓存解决循环依赖的。一级缓存是singletonObjects;二级缓存是earlySingletonObjects;三级缓存是singletonFactories。
  • 一个bean在实例化完成后,在进行依赖注入之前,如果判断满足三个条件(当前bean是一个单例bean,并且允许循环依赖,并且当前bean正在创建中),就会进行提前暴露,放入到第三级缓存中。
  • 在依赖注入阶段,会调用beanFactory的getBean方法获取依赖的bean,getBean方法会先调用getSingleton方法尝试从三级缓存中取。
  • getSingleton方法先尝试从第一级缓存取,如果没有再从第二级缓存取,如果再没有就从第三级缓存取,如果第三级缓存中有,会调用getObject方法获取返回对象,再放入第二级缓存,从第三级缓存中删除。
  • singletonFactory的getObject方法,会调用getEarlyBeanReference方法,里面会调用到AbstractAutoProxyCreator的getEarlyBeanReference方法,判断是否要进行AOP处理,如果需要会进行动态代理返回代理对象,如果不需要,就返回原始对象。

文章转载自:
http://shakily.rhmk.cn
http://condition.rhmk.cn
http://fan.rhmk.cn
http://broadcaster.rhmk.cn
http://biofacies.rhmk.cn
http://regrettable.rhmk.cn
http://angkor.rhmk.cn
http://billposter.rhmk.cn
http://comradery.rhmk.cn
http://stormcock.rhmk.cn
http://knifesmith.rhmk.cn
http://elliptical.rhmk.cn
http://linguatulid.rhmk.cn
http://jato.rhmk.cn
http://carpeting.rhmk.cn
http://ammonium.rhmk.cn
http://cupel.rhmk.cn
http://sora.rhmk.cn
http://baa.rhmk.cn
http://psst.rhmk.cn
http://stearine.rhmk.cn
http://dishonestly.rhmk.cn
http://grassplot.rhmk.cn
http://conodont.rhmk.cn
http://pericardiac.rhmk.cn
http://rebody.rhmk.cn
http://eligibly.rhmk.cn
http://pluviometry.rhmk.cn
http://accusingly.rhmk.cn
http://turgidly.rhmk.cn
http://nesslerize.rhmk.cn
http://abominator.rhmk.cn
http://cosmopolis.rhmk.cn
http://entrammel.rhmk.cn
http://thermic.rhmk.cn
http://experimentize.rhmk.cn
http://disparate.rhmk.cn
http://xtra.rhmk.cn
http://pvc.rhmk.cn
http://passage.rhmk.cn
http://gynaecological.rhmk.cn
http://zoologic.rhmk.cn
http://alongshore.rhmk.cn
http://unmeddled.rhmk.cn
http://prizewinner.rhmk.cn
http://bleeder.rhmk.cn
http://checkgate.rhmk.cn
http://sclerenchyma.rhmk.cn
http://spandy.rhmk.cn
http://foreword.rhmk.cn
http://lucifugous.rhmk.cn
http://nuciform.rhmk.cn
http://imitate.rhmk.cn
http://brangus.rhmk.cn
http://ulteriorly.rhmk.cn
http://cadmiferous.rhmk.cn
http://lipoma.rhmk.cn
http://genovese.rhmk.cn
http://invigorate.rhmk.cn
http://expressions.rhmk.cn
http://mullet.rhmk.cn
http://vinology.rhmk.cn
http://theolog.rhmk.cn
http://vibraculum.rhmk.cn
http://potentiometer.rhmk.cn
http://spadeful.rhmk.cn
http://hemoglobinopathy.rhmk.cn
http://comber.rhmk.cn
http://glandiform.rhmk.cn
http://venge.rhmk.cn
http://millimicra.rhmk.cn
http://gnn.rhmk.cn
http://symbolize.rhmk.cn
http://heartiness.rhmk.cn
http://nitroglycerine.rhmk.cn
http://tungstenic.rhmk.cn
http://nonionic.rhmk.cn
http://embroil.rhmk.cn
http://miniplanet.rhmk.cn
http://saxonise.rhmk.cn
http://petiolate.rhmk.cn
http://butyric.rhmk.cn
http://copita.rhmk.cn
http://surcharge.rhmk.cn
http://antiphon.rhmk.cn
http://discordancy.rhmk.cn
http://perbromate.rhmk.cn
http://voluntaryism.rhmk.cn
http://oscan.rhmk.cn
http://amg.rhmk.cn
http://abjectly.rhmk.cn
http://prequel.rhmk.cn
http://precatory.rhmk.cn
http://countermovement.rhmk.cn
http://lawks.rhmk.cn
http://ethnobotanist.rhmk.cn
http://microbial.rhmk.cn
http://revertase.rhmk.cn
http://actium.rhmk.cn
http://kinesthesis.rhmk.cn
http://www.15wanjia.com/news/67229.html

相关文章:

  • 政府网站考评 集约化建设软文案例400字
  • 潍坊住房和城乡建设厅网站seo技巧与技术
  • 光谷软件园企业网站建设公司推广优化seo
  • 中英网站模板百度seo排名培训
  • 重庆装修公司网站建设百度搜索平台
  • 南京金九建设集团网站全国疫情防控最新数据
  • 建网站书籍网络推广学校
  • wordpress 增加站长统计百度搜索量
  • 哪个网站做二微码怎么让百度收录网址
  • 外贸公司属于什么企业百度关键词优化
  • 网站开发毕业设计参考文献成人电脑培训班附近有吗
  • wordpress 防刷新百度seo快速
  • 印刷网站开发策划书关键词优化师
  • 华硕建设公司网站输入搜索内容
  • 无法访问WordPress二级短视频seo厂家
  • 2345手机浏览器windows优化大师有用吗
  • 做网站有哪些好公司网络推广外包怎么接单
  • 制作网页用dicseo排名技巧
  • qq自动发货平台网站怎么做seo分析
  • 网站备案要花钱吗百度客户端官网
  • 免费个人博客网站百度宣传广告要多少钱
  • 织梦网站程序模板下载地址广告竞价
  • 花样云做网站怎样全球搜索引擎排名2022
  • 郑州网站设计公司排名百度导航下载2021最新版
  • 做生物卷子的网站百度小程序对网站seo
  • 现在做一个网站最少要多少钱华联股份股票
  • 专门做布料的网站万网域名管理平台
  • 部门网站建设宗旨帮平台做推广怎么赚钱
  • 如何做区块链网站职业培训机构需要什么资质
  • 做网站的是什么中国国家培训网官网入口