spring三级缓存解决循环依赖

spring三级缓存解决循环依赖


前言

    我们都知道,在spring中属性的赋值是通过自动注入完成的,那么在自动注入的过程中它又是如何解决循环依赖的呢?


提示:本篇文章属于原创,请勿抄袭。

一、循环依赖

    要搞明白spring是如何解决循环依赖,首先我们要弄明白什么是循环依赖,如图所示:
spring三级缓存解决循环依赖
    有两个 service 对象,分别是 userService 和 orderService,它们各自都有一个引用对方的属性,互相循环引用着对方。

二、三级缓存

    在 spring 中,解决循环依赖主要是通过三级缓存来实现的,它们分别是:

  1. singletonObjects (一级缓存)
  2. earlySingletonObjects (二级缓存)
  3. singletonFactories (三级缓存)

对应的源码如下:


	// 一级缓存,存放的是已经实例化,并且初始化后的单例对象(也叫单例池)
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
	
	
	// 三级缓存,存放的是 ObjectFactory,通过 ObjectFactory 的 getObject()可以拿到已经实例化,但是并未初始化的对象
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);


	// 二级缓存,存放的是已经实例化,但是并未初始化的对象
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
	

三、spring解决循环依赖源码级别流程分析

    spring 源码中解决循环依赖的核心类是:DefaultSingletonBeanRegistry ,核心的代码如下:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 首先从一级缓存中获取对象
		Object singletonObject = this.singletonObjects.get(beanName);
		// 没有从一级缓存中获取到对象,并且当前对象正处于创建中
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 上锁,防止出现线程安全问题
			synchronized (this.singletonObjects) {
				// 从二级缓存中获取对象
				singletonObject = this.earlySingletonObjects.get(beanName);
				// 从二级缓存中没有获取到对象,并且这个对象允许提前暴露
				if (singletonObject == null && allowEarlyReference) {
					// 从三级缓存中获取 ObjectFactory 对象
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						// 通过调用 ObjectFactory 的 getObject() 获取(并不完整的)对象
						singletonObject = singletonFactory.getObject();
						// 把获取到的对象保存的二级缓存中
						this.earlySingletonObjects.put(beanName, singletonObject);
						// 从三级缓存中移除对象
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

    spring 解决循环依赖的详细执行流程如下:(当然这里面也省略了很多细节性的步骤,因为这里我们主要关注解决循环依赖的关键执行步骤)

  1. 首先在创建 userService 对象时,会调用 getBean() ,然后调用 doGetBean() 方法
  2. doGetBean() 会调用无回调函数的 getSingleton(beanName) 获取 userService 对象
  3. getSingleton() 方法会从 singletopnObjects (一级缓存中获取 userService ),如果没有获取到,则判断是否当前正在创建这个 userService ,如果当前没有正在创建,则直接返回 null
  4. 然后进行一系列的操作,接着调用有回调函数的 getSingleton(beanName,createBean()) 创建 userService
  5. 在创建 userService 之前先标记当前 userService 正在创建中,再调用回调函数 createBean()
  6. 回调函数 createBean(),再调用 doCreateBean(),接着调用 createBeanInstance() 创建 userService
  7. 创建完成后,未进行属性自动注入之前(即:实例化阶段之后,初始化阶段之前),调用 addSingletonFactory(),将创建好的 userService 包装成 ObjectFactory 然后放入 singletonFactories(三级缓存)中
  8. 调用 populateBean() 进行属性自动注入,然后去创建需要自动注入的依赖对象 orderService
  9. 重复 (1-8 )步骤去创建 orderService
  10. 创建完 orderService 之后,调用 populateBean() 方法,进行依赖注入 userService
  11. 然后调用 getBean() (和前面的 1-3 步一样)获取 userService ,然后从 singletonFactories (三级缓存) 中获取 ObjectFactory
  12. 接着调用 ObjectFactory 的 getObject 方法,getObject() 方法会从三级缓存中获取 userService (此时的 userService 对象还不是一个完整的对象,它的 orderService 属性是为 null 的,因为还没有对 userService 执行自动注入的),然后将 userService 保存到 earlySingletonObjects(二级缓存)中,并从 singletonFactories(三级缓存)中移除
  13. 然后给 orderService 对象的 userService 属性赋值为二级缓存中保存的 userService 对象(这一步就是所谓的自动依赖注入了,虽然此时的 userService 还不是一个完整的对象,但是 orderService 的 userService 属性保存的也只是 userService 对象的引用地址而已,所以和 userService 当前是否为一个完整的对象是没有什么关系的,因为此时此刻,还没有人去用这个对象
  14. 最后调用 initializeBean() 方法,完成 orderService 的最后初始化
  15. 最后再调用 addSingleton() 方法,将创建好并初始化好的 orderService 对象放入singletonObjects(一级缓存)中,并从三级缓存(singletonFactories )中移除 orderService
  16. 然后回到创建 userService 的生命周期中,继续给 userService 的 orderService 属性自动注入
  17. 最后结束 userService 的整个创建生命周期,并调用 addSingleton() 方法将 userService 从二级缓存中移除,并添加到一级缓存中
上一篇:2021-12(java-springcloud学习笔记二eureka)


下一篇:基于Spring Boot 和Spring Cloud和Docker的微服务架构项目实战