循环依赖:多个对象之间存在循环的引用关系,在初始化过程当中,就会出现"先有蛋还是先有鸡"的问题。
解决方法:
一种是 使用@Lazy注解,另一种是使用三级缓存。
@Lazy注解:解决构造方法造成的循环依赖问题。
一级缓存:缓存最终的单例池对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
二级缓存:缓存初始化的对象
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
三级缓存:缓存对象的ObjectFactory
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
解决方式一:@Lazy
一个快速解决的方式,就是在B的构造方法上加一个@Lazy注解,延迟加载
解决方式二:@Autowired
对于对象之间的普通引用,
二级缓存会保存new出来的不完整对象,这样当单例池中找不到依赖的属性时,就可以先从二级缓存中获取到不完整对象,完成对象创建,在后续的依赖注入过程中,
将单例池中对象的引用关系调整完成。
三级缓存:如果引用的对象配置了AOP,那在单例池中最终就会需要注入动态代理对象,而不是原对象。而生成动态代理是要在对象初始化完成之后才开始的。
于是,Spring增加三级缓存,保存所有对象的动态代理配置信息。在发现有循环依赖时,将这个对象的动态代理信息获取出来,提前进行AOP,生成动态代理。
核心代码就在DefaultSingletonBeanRegistry的getSingleton方法当中。