Spring中的循环依赖问题

文章目录

  • 前言
  • 一、什么是循环依赖?
  • 二、三级缓存
  • 三、图解
  • 三级缓存总结


前言

本文章将讲解Spring循环依赖的问题


一、什么是循环依赖?

一个或多个对象之间存在直接或间接的依赖关系,这种依赖关系构成一个环形调用,有下面 3 种方式。

Spring中的循环依赖问题_第1张图片

模拟一个情况2的Demo

@Service
public class Service {
	@Autowried
	Dao dap;
}
@Repository
class Dao{
	@Autowried
	Service service;
}

Spring中的循环依赖问题_第2张图片

这是一个经典的循环依赖,如果spring没有处理循环依赖,那么在他们需要注入对方属性时,会一直循环等待对方注入属性,导致无限循环。

二、三级缓存

Spring为了解决循环引用的问题,提供了三级缓存的存储方式

public class DefaultSingletonBeanRegistry ... {
//1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三
级缓存"
Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
注:将对象保存至三级缓存的时候,会包装成ObjectFactory对象录入,未来通过此接口对应的get方法再
次提取对象

三、图解

Spring中的循环依赖问题_第3张图片

图解描述:

  • A实例化对象,但尚未初始化,将A存储到三级缓存中;
  • A属性注入,发现需要B对象,从缓存中取,发现没有B对象;
    • B实例化对象,但尚未初始化,将B放到三级缓存
    • B属性注入,需要A对象,从三级缓存中通过工厂获取A对象,再将A从三级缓存移除到二级缓存,
    • B执行其他生命周期的过程,最终成为一个完全体Bean,存储到一级缓存,删除二三级缓存
  • A注入B对象
  • A执行其他生命周期过程,最终成为一个完全体Bean,存储到一级缓存,删除二三级缓存

三级缓存总结

  • 一级缓存:为“Spring 的单例属性”而生 ,就是个单例池,用来存放已经初始化完成的单例 Bean;
  • 二级缓存:为“解决 AOP”而生 ,存放的是半成品的 AOP 的单例 Bean;
  • 三级缓存:为“打破循环”而生 ,存放的是生成半成品单例 Bean 的工厂方法

如果没有AOP的话,其实只需要一、三级缓存,就可以解决循环引用的问题;

你可能感兴趣的:(spring,java,后端)