spring如何解决循环依赖

944 阅读2分钟

什么是循环依赖

循环依赖指的是两个bean互相依赖彼此,beanA在示例化的时候要注入beanB,beanB在实例化的时候要注入beanA,导致两者互相依赖谁都不能实例化成功的情况。

image.png

但是,在spring中,如果我们创建了两个bean,彼此注入对方,在spring上下文初始化的时候却可以帮我们构建出两个完成体的springbean,那spring是怎么做到的呢?

解决循环依赖的方法

在实际探索源码的过程中,发现spring解决这个问题主要是采用了三级缓存解决了彼此依赖的问题,下面让我们回顾一下流程。 首先,定义两个bean

package com.zt.beans;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TestBeanA {
	@Autowired
	TestBeanB testBeanB;
}
package com.zt.beans;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TestBeanB {
	@Autowired
	TestBeanA testBeanA;
}

可以看到,beanA和beanB互相持有彼此,接下来我们通过ApplicationContext获取testBeanA。

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class CircleDependTest {
	@Test
	public void testCircleDepend() {
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.zt.beans");
		Object testBeanA = applicationContext.getBean("testBeanA");
		System.out.println(testBeanA);
	}
}

输出结果 image.png TestBeanA创建成功。

三级缓存

一级缓存:singletonObjects 存储构建完成的spring bean对象

二级缓存:earlySingletonObjects 存储三级缓存加工过的对象,此时spring bean 还未构建完成

三级缓存:singletonFactories 存储刚刚构建的bean工厂,实际是一个回调函数。

BeanA构建流程

1、调用beanA的无参构造方法,将beanA放入三级缓存中,标记beanA正在构建中

2、为beanA属性赋值,此时发现,beanA依赖于beanB,从IOC容器中获取beanB

3、beanB此时还为构建,调用beanB的无参构造方法,将beanB放入三级缓存中

4、为beanB属性赋值,此时发现,beanB依赖于beanA,从IOC容器中获取beanA

5、beanA此时正在构建中,从三级缓存中获取beanA,将beanA从三级缓存移除,放入二级缓存中(此步骤可以拓展)

6、将未完全构建完成的beanA赋值给beanB,beanB构建完成,讲beanB放入一级缓存中,并清空二级、三级缓存中的beanB(此步骤spring会统一再次清空缓存)

7、beanA获取到构建完成的beanB,讲beanB赋值给beanA,beanA构建完成,将beanA放入一级缓存中,beanA构建完成。