谈谈spring中的循环依赖

spring是如何解决循环依赖的,下面我将通过查看Spring源码,谈谈我自己的看法。

(以下的分析基于spring5.0版本源码,可以自行编译spring源码。)

一、问题描述

@Component
public class IndexDao {
	@Autowired
	private IndexService indexService; //在indexDao中引用了indexService
}

@Component
public class IndexService {
	@Autowired
	private IndexDao indexDao; //在indexService中引用了indexDao
}

在IndexDao中定义IndexServic属性并加上了@Autowired的注解,在IndexService中定义了IndexDao的属性,并加上了@Autowired注解自动装配。这就是循环引用。

二、问题分析

1、对象与bean
对象:java的普通对象
spring bean:也是Java的对象,但是它是存在spring容器中,并且是结果了完整的spring bean的实例化和初始化过程的(也可以说是拥有了完整的spring bean的生命周期的)。
2、分析
1、先来看看IndexDao是怎么初始化的

public class Test {
		public static void main(String[] args) {
			AnnotationConfigApplicationContext acc = new AnnotationConfigApplicationContext(AppConfig.class);
		}
	}

AnnotationConfigApplicationContext 我们利用这个类来初始化我们的spring环境,然后通过debug一步步跟进。
当我们去创建IndexDao的时候,回去容器中先拿看有没有这个bean会调用getBean这个方法,所以在getBean的时候打一个条件断点来跟进。然后debug运行Test的main方法。

  1. getBean
    在这里插入图片描述

  2. doGetBean
    在这里插入图片描述

  3. getSingleton(beanName)---->getSingleton(beanName, true);
    在这里插入图片描述
    在这里插入图片描述

  4. 接下来会调用 getSingleton(String beanName, ObjectFactory<?> singletonFactory)
    在这里插入图片描述
    在这里插入图片描述

  5. 接下来会调用 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

    ----->调用doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)

    ----->调用 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    在这里插入图片描述在这里插入图片描述

  6. 调用 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    在这里插入图片描述

  7. 调用populateBean(beanName, mbd, instanceWrapper); 填充属性
    在这里插入图片描述
    会调用org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues这个方法来进行@Autowired的属性填充。在IndexDao需要填充的属性是IndexService。同样的它还是会调用getBean方法从容器中去拿IndexService,所以我们在org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)方法中打一个条件断点,name.equals(“indexService”).

  8. 调用org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
    在这里插入图片描述
    调用getBean之后的流程就和我们之前创建IndexDao的流程是一样的了,先从容器中去拿,没有的话就创建,然后填充属性。
    getBean----->doGetBean------->getSingleton----->createBean—>doCreateBean—>populateBean–>postProcessPropertyValues
    最后在IndexService被创建出来了以后,它会去进行属性填充,调用getBean(indexDao),所以我们再到org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)这里打一个条件断点name.equals(“indexDao”)
    在这里插入图片描述
    此时getBean会调用到 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)这个方法,我们再来debug一下这里。
    在这里插入图片描述

  9. 最后会调用field.set(bean, value);这个方法给属性赋值

这里的第一次赋值是IndexService中的IndexDao属性赋值。属性赋值之前
在这里插入图片描述
第一次属性赋值之后
在这里插入图片描述
这样我们的IndexService中就已经引用上了IndexDao,只不过此时的IndexDao中的IndexService属性为null。

同样的道理,当我们第二次调用这个方法给属性赋值时,就可以发现此时我们的IndexDao也已经引用好了我们的IndexService。
第二次属性赋值之前
在这里插入图片描述
第二次属性赋值之后

当调用完这行代码后 我们的循环依赖就完成了。

三、总结

IndexDao—getBean—doGetBean–getSingleton(String beanName, boolean allowEarlyReference)(第一次)–getSingleton(String beanName, ObjectFactory<?> singletonFactory)–creatBean–doCreateBean–populateBean(填充属性)–initializeBean(初始化bean)
IndexService也是一样的流程。
简单来说就是利用了singletonFactories 这样一个Map的数据结构来缓存了一下我们还没有完成springBean的生命周期的对象。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值