Springboot循环依赖

一、依赖注入的几种方式:

1. Set方式注入

1
2
3
4
5
6
7
8
public class TestServiceImpl implents TestService{
private TestDao testDao;

@Autowire
public serTestDao(TestDao testDao){
this.testDao = testDao;
}
}

2. 构造函数注入

1
2
3
4
5
6
7
8
public class TestServiceImpl implents TestService{
private TestDao testDao;

@Autowire
public TestServiceImpl(TestDao testDao){
this.testDao = testDao;
}
}

3. 注解注入

@Resouece@Autowired@Inject注入

1
2
3
4
5
6
7
8
public class TestServiceImpl implents TestService{
@Autowire
private TestDao testDao;
//@Resouece
//private TestDao testDao;
// @Inject
//private TestDao testDao;
}
注解 描述
@Resouece 通过CommonAnnotationBeanPostProcessor.class实现,属性(name=“**”)指定属性
@Autowired ,当属性required=fales时找不到想对应的Bean不会报错
@Inject+@Named @Inject是jsr330中的规范,跟@Autowired一样通过AutowiredAnnotationBeanPostProcessor.class实现,按类型来查询Bean,@Named注解用于配置与变量名不一致时
@Qualifier 通常跟@Resource一起使用,显示指定导入的Bean

二、循环依赖

1. 循环依赖场景

  • A、B两个对象之间互相依赖
  • A、B、C之间形成环形依赖(Bean A→Bean B→Bean C→Bean A)
  • A对象依赖自身

Bean A 依赖 B,Bean B 同时依赖 A这种情况下出现循环依赖,如下:

Bean A->Bean B->Bean A

但当存在循环依赖时,Spring将无法决定先创建哪个bean,spring将抛出BeanCurrentlyInCreationException异常

2. 解决方法

2.1. 使用注解@lazy

1
2
3
4
5
6
7
8
9
//@lazy为延迟加载。在注入依赖时,先注入代理对象,当首次使用时再创建对象完成注入。
public class TestServiceImpl implents TestService{
private TestDao testDao;

@Autowire
public TestServiceImpl(@Lazy TestDao testDao){
this.testDao = testDao;
}
}

2.2. 使用Setter/Field注入

1
//Spring文档建议的一种方式是使用setter注入。当依赖最终被使用时才进行注入。

2.3. 实现ApplicationContextAware和InitializingBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component
public class TestA implents ApplicationContextAware, InitializingBean{
private TestB testB;

private ApplicationContext context;

public TestB testB() {
return testB;
}

@Override
public void afterPropertiesSet() throws Exception {
testB = context.getBean(TestB.class);
}

@Override
public void setApplicationContext(final ApplicationContext ctx) throws BeansException {
context = ctx;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Component
public class TestB {

private TestA testA;

private String message = "Hi!";

@Autowired
public void setTestA(TestA testA) {
this.testA = testA;
}

public String getMessage() {
return message;
}
}

三、Spring采用三级缓存解决循环依赖

获取Bean源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
//第1级缓存 用于存放 已经属性赋值、完成初始化的 单列BEAN
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//第2级缓存 用于存在已经实例化,还未做代理属性赋值操作的 单例BEAN
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//第3级缓存 存储创建单例BEAN的工厂
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//已经注册的单例池里的beanName
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
//正在创建中的beanName集合
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
//缓存查找bean 如果第1级缓存没有,那么从第2级缓存获取。如果第2级缓存也没有,那么从第3级缓存创建,并放入第2级缓存。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName); //第1级
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName); //第2级
if (singletonObject == null && allowEarlyReference) {
//第3级缓存 在doCreateBean中创建了bean的实例后,封装ObjectFactory放入缓存的bean实例
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//创建未赋值的bean
singletonObject = singletonFactory.getObject();
//放入到第2级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
//从第3级缓存删除
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
}

添加到第1级缓存的源码

1
2
3
4
5
6
7
8
9
10
11
12
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 放入第1级缓存
this.singletonObjects.put(beanName, singletonObject);
// 从第3级缓存删除
this.singletonFactories.remove(beanName);
// 从第2级缓存删除
this.earlySingletonObjects.remove(beanName);
// 放入已注册的单例池里
this.registeredSingletons.add(beanName);
}
}

添加到第3级缓存的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
// 若第1级缓存没有bean实例
if (!this.singletonObjects.containsKey(beanName)) {
// 放入第3级缓存
this.singletonFactories.put(beanName, singletonFactory);
// 从第2级缓存删除,确保第2级缓存没有该bean
this.earlySingletonObjects.remove(beanName);
// 放入已注册的单例池里
this.registeredSingletons.add(beanName);
}
}
}

创建Bean源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;

if (instanceWrapper == null) {
//实例化对象
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}

final Object bean = instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null;
Class<?> beanType = instanceWrapper != null ? instanceWrapper.getWrappedClass() : null;

//判断是否允许提前暴露对象,如果允许,则直接添加一个 ObjectFactory 到第3级缓存
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
//添加到第3级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

//填充属性
this.populateBean(beanName, mbd, instanceWrapper);
//执行初始化方法,并创建代理
exposedObject = initializeBean(beanName, exposedObject, mbd);
return exposedObject;
}

四、三级缓存执行流程

例子:A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象

  1. A 调用doCreateBean()创建Bean对象:由于还未创建,从第1级缓存singletonObjects查不到,此时只是一个半成品(提前暴露的对象),放入第3级缓存singletonFactories
  2. A在属性填充时发现自己需要B对象,但是在三级缓存中均未发现B,于是创建B的半成品,放入第3级缓存singletonFactories
  3. B在属性填充时发现自己需要A对象,从第1级缓存singletonObjects和第2级缓存earlySingletonObjects中未发现A,但是在第3级缓存singletonFactories中发现A,将A放入第2级缓存earlySingletonObjects,同时从第3级缓存singletonFactories删除。
  4. 将A注入到对象B中。
  5. B完成属性填充,执行初始化方法,将自己放入第1级缓存singletonObjects中(此时B是一个完整的对象),同时从第3级缓存singletonFactories 和第2级缓存earlySingletonObjects中删除
  6. A得到“对象B的完整实例”,将B注入到A中。
  7. A完成属性填充,执行初始化方法,并放入到第1级缓存singletonObjects中。

提前暴露的对象,虽然已实例化,但是没有进行属性填充,还没有完成初始化,是一个不完整的对象。 这个对象存放在二级缓存中,对于三级缓存机制十分重要,是解决循环依赖一个非常巧妙的设计。在创建过程中,都是从第三级缓存(对象工厂创建不完整对象),将提前暴露的对象放入到第二级缓存;从第二级缓存拿到后,完成初始化,并放入第一级缓存。