0
点赞
收藏
分享

微信扫一扫

Spring循环依赖原理和Bean创建过程


Spring循环依赖

1.什么是循环依赖

循环依赖就是指Spring在创建Bean的过程中,一个Bean的属性依赖另一个Bean,而被依赖的Bean又依赖于当前Bean,如下图所示:

Spring循环依赖原理和Bean创建过程_bean

代码如下:

StudentService.java

public class StudentService {

private TeacherService teacherService;

//因为要依赖注入,在这里我们先使用setter注入
public void setTeacherService(TeacherService teacherService) {
this.teacherService = teacherService;
}

static {
System.out.println("创建StudentServiceBean...");
}
}

TeacherService.java

public class TeacherService {

private StudentService studentService;

public void setStudentService(StudentService studentService) {
this.studentService = studentService;
}

static {
System.out.println("创建teacherServiceBean...");
}
}

测试:

@Test
public void beanTest01() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
{
RootBeanDefinition stu = new RootBeanDefinition(StudentService.class);
HashMap<String, Object> map = new HashMap<>();
map.put("teacherService", new RuntimeBeanReference("teacherService"));
stu.setPropertyValues(new MutablePropertyValues()
.addPropertyValues(map));
factory.registerBeanDefinition("studentService", stu);
}

{
RootBeanDefinition tea = new RootBeanDefinition(TeacherService.class);
HashMap<String, Object> map = new HashMap<>();
map.put("studentService", new RuntimeBeanReference("studentService"));
tea.setPropertyValues(new MutablePropertyValues()
.addPropertyValues(map));
factory.registerBeanDefinition("teacherService", tea);
}
StudentService bean = factory.getBean(StudentService.class);
System.out.println(bean);
}

debug一下看看效果:

Spring循环依赖原理和Bean创建过程_java_02

显然,Spring创建的都是单例的Bean,循环依赖的完成也是由Spring自动进行的,下面我们从创建bean开始来了解Spring是如何解决循环依赖的。

2.Spring创建对象的过程

2.1 大致过程

大致过程无非就是这样:

Spring循环依赖原理和Bean创建过程_创建对象_03

2.2 实际创建过程

详细过程就需要涉及到工厂模式、抽象工厂、单例池…

Spring循环依赖原理和Bean创建过程_java_04

主要类的依赖图(全部为继承关系):

Spring循环依赖原理和Bean创建过程_bean_05

  • 首先调用公开方法 DefaultListableBeanFactory.getBean(Class cls) 来获取 Bean 对象,通过一系列操作转化 class 对象为 beanName。
  • 得到beanName之后,调用 AbstractBeanFactory.getBean(String name, Class cls) , 在这个方法中又会调用受保护的 AbstractBeanFactory.doGetBean 方法
  • doGetBean方法中,又会调用 DefaultSingletonBeanFactory.getSingleton(String beanName, ObjectFactory factory)
  • getSingleton方法中,首先在单例池 DefaultSingletonBeanFactory.singletonObjects 查找是否已经存在 beanName 对应的单例对象。如果找不到,那会调用函数式接口ObjectFactory来创建一个对象,而这个对象工厂调用的函数是一个受保护的抽象方法 AbstractBeanFactory.crateBean(String beanName, RootBeanDefinition def, Object[] args)
  • AbstractAutowireCapableBeanFactory实现了超类的createBean方法, 并在createBean方法中调用了受保护的方法 AbstractAutowireCapableBeanFactory.doCreateBean
  • doCreateBean方法中,还会调用 AbstractAutowireCapableBeanFactory.populateBean 来填充属性。
  • populateBean填充属性时,还可能遇上没有创建过的对象,因此还可能递归调用AbstractBeanFactory.getBean(String beanName)

​AbstractAutowireCapableBeanFactory 负责了实例化 Bean,填充属性,后置处理的任务,DefaultSingletonBeanRegistry 负责了单例池的维护工作​

3.Spring是如何解决循环依赖的

Spring循环依赖原理和Bean创建过程_spring_06

​Spring 就是靠获取未完成的Bean对象来填充属性,解决循环依赖的。(这里使用到了三级缓存)​

基本过程:

(1)通过getSingleton()时添加,Bean创建状态

(2)实例化Bean之后添加ObjectFactory至工厂池

(3)获取创建状态的Bean时,会先通过ObjectFactory获取Bean,然后添加到半成品池earlySingletonObjects

(4)对象完成创建后会添加到单例池

为什么不直接把对象放入 earlySingletonObjects,而是先放入 singletonFactories 中?

创建对象是需要消耗性能的,假如创建没有循环依赖的对象,是不需要创建未完成的Bean对象的,所以不是直接创建未完成对象放入未完成单例集 earlySingletonObjects,而是把未完成单例工厂放入 singletonFactories

比如以下这段代码,在运行时就不会调用 getSingleton 中的 ObjectFactory.getObject() 方法来创建未完成 Bean 对象。

4.什么情况下不能解决循环依赖

​在Bean是多例的状态下不能解决循环依赖(因为按理来说要创建无数个Bean)​

试一下:

@Test
public void beanTest01() {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
{
RootBeanDefinition stu = new RootBeanDefinition(StudentService.class);
HashMap<String, Object> map = new HashMap<>();
map.put("teacherService", new RuntimeBeanReference("teacherService"));
stu.setPropertyValues(new MutablePropertyValues()
.addPropertyValues(map));
stu.setScope("prototype"); //将StudentService设置为多例模式
factory.registerBeanDefinition("studentService", stu);
}

{
RootBeanDefinition tea = new RootBeanDefinition(TeacherService.class);
HashMap<String, Object> map = new HashMap<>();
map.put("studentService", new RuntimeBeanReference("studentService"));
tea.setPropertyValues(new MutablePropertyValues()
.addPropertyValues(map));
factory.registerBeanDefinition("teacherService", tea);
}
StudentService bean = factory.getBean(StudentService.class);
System.out.println(bean);
}

报错:

Spring循环依赖原理和Bean创建过程_bean_07

参考文章:


PS:有些地方可能解释的不太清楚,欢迎读者提出建议




举报

相关推荐

0 条评论