两个流程理论上是互不影响的


protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)throws BeansException {// bean名称转换// 根据指定的名称获取被管理bean的名称// 如果指定是别名,将别名转换为规范的Bean名称String beanName = transformedBeanName(name);Object bean;​// 从各级缓存中获取bean对象Object sharedInstance = getSingleton(beanName);// 这个判断是跟factoryBean相关的if (sharedInstance != null && args == null) {if (logger.isTraceEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.trace("Returning cached instance of singleton bean '" + beanName + "'");}}bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}​......​// 创建bean对象if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}​......// 返回bean对象return (T) bean;}

我们重点看两个getSingleton()方法


// 这段代码三级缓存容器都涉及到了,初看有点懵,但是思路不难,先从一级缓存找,找不到去二级缓存找,还找不到去三级缓存// 如果在三级缓存找到了,就放到二级缓存中,非常像数据库跟redis的缓存策略,先到redis中找,找不到去数据库找,找到再写到redis中protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 先从一级缓存中找beanObject singletonObject = this.singletonObjects.get(beanName);// 这里有两个判断,singletonObject == null 表示在一级缓存中找不到bean// isSingletonCurrentlyInCreation()表示该bean是否在创建中// 如果两个条件满足,说明出现了循环依赖if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 再从二级缓存中获取singletonObject = this.earlySingletonObjects.get(beanName);// 这里又有两个判断// singletonObject == null 表示在二级缓存中没有获取到// allowEarlyReference 这个值传进来就为true,表示是否允许获取早期引用// 如果两个条件都满足,就到三级缓存中获取if (singletonObject == null && allowEarlyReference) {// 从三级缓存获取,注意,这里获取到是一个ObjectFactoryObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 通过ObjectFactory获取bean实例singletonObject = singletonFactory.getObject();// 打怪升级,从三级缓存升级到二级缓存,this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}// 返回beanreturn singletonObject;}

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {

Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {

// 从一级缓存中获取bean

  Object singletonObject = this.singletonObjects.get(beanName);

// 如果bean为空

  if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while singletons of this factory are in destruction " +"(Do not request a bean from a BeanFactory in a destroy method implementation!)");}if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}

// 单例bean创建前会将这个bean放到一个容器中,标志这个bean正在创建中

    beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {

// 执行匿名内部类方法

      singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;}finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}

// 单例bean创建完成后,会把bean从这个容器中移除

      afterSingletonCreation(beanName);}

// newSingleton为true时,表示bean创建成功

    if (newSingleton) {

// 把bean放到一级缓存中,一级缓存就是我们常说的IOC容器

      addSingleton(beanName, singletonObject);}}return singletonObject;}

}


protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {// 放进一级缓存中this.singletonObjects.put(beanName, singletonObject);// 从三级缓存中移除this.singletonFactories.remove(beanName);// 从二级缓存中移除this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}```从上面的代码我们已经可以总结出bean没有出现循环依赖时,流程是怎么样的?1.  getSingleton()方法查看是否存在于一级缓存中,是则获取,无则走下面的创建流程,因为没有出现循环依赖,isSingletonCurrentlyInCreation(beanName),此判断是false2.  createBean()方法创建一个bean3.  addSingleton()方法将bean放到一级缓存中当然,在正常的流程中会穿插异常流程的处理方式,比如bean创建前会把bean放到一个容器中,Spring凭借这个可以知道bean是否正在创建中,得知bean在创建中后,会利用三级缓存获得bean空壳```protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {​....​// mbd.isSingleton():bean是否是单例// this.allowCircularReferences:是否允许出现循环依赖// isSingletonCurrentlyInCreation(beanName):bean是否在创建中// 如果三个条件都满足,说明出现了循环依赖boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}// 将bean放到三级缓存中addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}​// Initialize the bean instance.Object exposedObject = bean;try {// 属性赋值populateBean(beanName, mbd, instanceWrapper);// bean初始化exposedObject = initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}// 如果出现了循环依赖if (earlySingletonExposure) {// 从各级缓存中获取bean,getSingleton(beanName, false)这个方法是不是很熟悉,上面已经使用到了// 只是第二个参数从true变成了false,这个参数决定了要不要从第三级缓存中获取数据// 代码走到这个地方,已经无需获取早期引用了,所以参数为falseObject earlySingletonReference = getSingleton(beanName, false);// 如果二级缓存不为空if (earlySingletonReference != null) {// 并且二级缓存中的bean跟exposedObject相等,说明初始化时,没有使用代理修改bean对象if (exposedObject == bean) {// 直接将二级缓存中bean返回即可exposedObject = earlySingletonReference;}....​return exposedObject;}```我们重点看看addSingletonFactory()这个方法,我们先看一段简单代码,感受一下ObjectFactory这个类的作用```public class ObjectFactoryTest {​​public static void main(String[] args) {HashMap<String, ObjectFactory<?>> map = new HashMap<>(2);map.put("a", () -> {System.out.println("objectFactory");return "string";});​System.out.println(map.get("a").getObject());}}```![image.png](https://img-blog.csdnimg.cn/img_convert/0a437e603e6bbb7208ac92b516a6703c.png) 原来,ObjectFactory可以定制执行方法,那么Spring要定制的执行方法是什么?```protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {// 放入三级缓存this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}}

// 要定制的执行方法就是一个beanPostProcess的埋点

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {

Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {

最后

送大家一个小福利,点击领取Java全套进阶资料

etons.add(beanName);

  }}

}


// 要定制的执行方法就是一个beanPostProcess的埋点protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {# 最后**[送大家一个小福利,点击领取Java全套进阶资料](https://gitee.com/vip204888/java-p7)**[外链图片转存中...(img-60Y6qU4z-1628591179093)][外链图片转存中...(img-cR7POWt5-1628591179096)]![](https://img-blog.csdnimg.cn/img_convert/75d03bc41b86865b384048958c2070a0.png)

Spring源码解析-三级缓存与循环依赖,nginx架构图相关推荐

  1. spring源码解析(五) 循环依赖

    1.什么是循环依赖? Bean A → Bean B → Bean A 在A对象生命周期中注入B,进入B生命周期找A,但A还不存在,继续进入A对象生命周期找B,这就是循环依赖. 2.循环依赖造成的结果 ...

  2. Spring 源码总结、IOC、循环依赖、AOP分析

    Spring 源码 本文基于 jdk 11 核心类 interface BeanFactory 该接口是访问 Spring bean 容器的根接口,是 bean 容器的基本客户端视图: 其他接口如Li ...

  3. spring源码阅读笔记09:循环依赖

    前面的文章一直在研究Spring创建Bean的整个过程,创建一个bean是一个非常复杂的过程,而其中最难以理解的就是对循环依赖的处理,本文就来研究一下spring是如何处理循环依赖的. 1. 什么是循 ...

  4. Spring-bean的循环依赖以及解决方式___Spring源码初探--Bean的初始化-循环依赖的解决

    本文主要是分析Spring bean的循环依赖,以及Spring的解决方式. 通过这种解决方式,我们可以应用在我们实际开发项目中. 什么是循环依赖? 怎么检测循环依赖 Spring怎么解决循环依赖 S ...

  5. 别盲从了,spring 解决循环依赖真的一定需要三级缓存吗?demo结合源码讲解三级缓存的真正目的,一级缓存singletonFactories的真正作用,看到文章最后让面试官眼前一亮

    背景 本篇是我上一篇<3分钟秒懂,最简单通俗易懂的spring bean 生命周期介绍与源码分析,附上demo完整源码>姊妹篇 spring 三级缓存问题是面试中的热点问题,大部分回答者会 ...

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

    人人都能看懂的Spring源码解析,Spring如何解决循环依赖 原理解析 什么是循环依赖 循环依赖会有什么问题? 如何解决循环依赖 问题的根本原因 如何解决 为什么需要三级缓存? Spring的三级 ...

  7. Spring 源码解析 - Bean创建过程 以及 解决循环依赖

    一.Spring Bean创建过程以及循环依赖 上篇文章对 Spring Bean资源的加载注册过程进行了源码梳理和解析,我们可以得到结论,资源文件中的 bean 定义信息,被组装成了 BeanDef ...

  8. 京东一面:Spring 为何需要三级缓存解决循环依赖,而不是二级缓存?我懵了。。...

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:cnblogs.com/semi-sub/p/13548479.html 前言 bean生命周期 三级缓存解决循环依赖 总结 ...

  9. Spring源码解析 - AbstractBeanFactory 实现接口与父类分析

    2019独角兽企业重金招聘Python工程师标准>>> 我们先来看类图吧: 除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegi ...

最新文章

  1. PySpark安装和测试
  2. 通过虚方法实现方法重写-多态
  3. eureka配置_F版本SpringCloud 5—Eureka集群和自我保护机制
  4. leetcode - 1025. 除数博弈
  5. 微信公开课讲师王泓渊:小游戏开放能力
  6. Eclipse没有Web插件和JavaEE插件咋整
  7. Request中Attribute 和 Parameter 的区别
  8. eclipse JSP页面中的JS代码为黑色,JS单独文件是OK的
  9. 手机变Android麦克风,手机变麦克风
  10. java计算机毕业设计高校多媒体设备报修管理系统源码+mysql数据库+系统+lw文档+部署
  11. Python中的二维数组定义
  12. 合并Windows系统镜像教程
  13. Stimulsoft Reports.JS 2021.3.6 Crack
  14. MIT线性代数笔记三 矩阵的乘法和逆矩阵
  15. MIGO结合NFT技术带来全新DeFi金融平台
  16. debian nvidia 安装_在 Debian 上安装 Nvidia 显卡驱动启用 Nvenc
  17. java编译方法参数(-parameters)名为arg0问题
  18. Foreign Language_english_感叹句
  19. 2018秋季寒假作业2-记叙在人生路上对我影响最大的三位老师
  20. 在c语言中有逻辑型变量吗,【判断题】在C语言中,虽然有逻辑运算,但没有逻辑型变量....

热门文章

  1. c++ opencv 基本操作
  2. torchvision nms
  3. Opencv 去高光或镜面反射(illuminationChange)
  4. layui table 列覆盖
  5. 遗传算法入门到掌握(一)
  6. python 排列组合之itertools
  7. opencv 图像阴影检测
  8. 多线程还是多进程的区别
  9. 清华学计算机的住在哪个公寓,清华附近住宿情况一览
  10. 2021揭东一中今年高考成绩查询入口,2021年揭阳高考状元是谁分数多少分,历年揭阳高考状元名单...