Spring-循环依赖

发布于:2024-09-19 ⋅ 阅读:(6) ⋅ 点赞:(0)

预备知识

循环依赖开关(方法) - AbstractAutowireCapableBeanFactory#setAllowCircularReferences

  • 单例工程(属性) - DefaultSingletonBeanRegistry#singletonFactories
  • 获取早期未处理Bean (方法) - AbstractAutowireCapableBeanFactory#getEarlyBeanReference
  • 早期未处理Bean (属性) - DefaultSingletonBeanRegistry#earlySingletonObjects

循环依赖处理流程

案例代码:

@Component
public class ClassRoom {
    @Autowired
    private Collection<Student> students;

    public Collection<Student> getStudents() {
        return students;
    }

    public void setStudents(Collection<Student> students) {
        this.students = students;
    }
}
@Component
public class Student {
    @Autowired
    private ClassRoom classRoom;

    public ClassRoom getClassRoom() {
        return classRoom;
    }

    public void setClassRoom(ClassRoom classRoom) {
        this.classRoom = classRoom;
    }
}

这个例子ClassRoom里面注入了Student,Student里面又注入了ClassRoom。

首先要确保我们的循环依赖是单例的,然后再初始化单例Bean的时候会调用doGetBean方法,然后进入AbstractBeanFactory#doGetBean方法:
在这里插入图片描述
在getSington方法里面beforeSingletonCreation,有这样一个方法,这个方法会将当前正在创建的单例Bean放到singletonsCurrentlyInCreation中:
在这里插入图片描述
接着会调用我们拉姆达表达式穿进来的工厂createBean获取Bean,会判断是不是正在创建的Bean
在这里插入图片描述
如果是的话(前面在beforeSingletonCreation将当前创建的Bean放到了singletonsCurrentlyInCreation所以这里肯定是),会调用addSingletonFactory,会传进去一个拉姆达表达式:
在这里插入图片描述
这个时候singletonFactories就会存贮,并且earlySingletonObjects如果存在会移除这个Bean,同时将这个Bean放到已注册中:
在这里插入图片描述
接着就是这个Bean的populateBean逻辑,对依赖进行注入会处理依赖doResolveDependency:
在这里插入图片描述
由于我们注入Students是一个集合,所以会走multipleBeans这个处理:
在这里插入图片描述
这个时候又去getBean了,这个和我们上面ClassRoom走的是一样的流程,这个时候已经有两个了:
在这里插入图片描述
在Student注入的时候发现注入的字段又需要ClassRoom,于是又会去resolveDependency:
在这里插入图片描述
这个时候earlySingletonObjects里面没有,所以拿到了我们上面的singletonFactories中的singleFactory了,在拿到Bean以后就将singletonFactories中的移除了,同时将它放到earlySingletonObjects:
在这里插入图片描述
然后将这个ClassRoom的Bean注入到Student中:
在这里插入图片描述
我们可以看到这个时候ClassRoom里面是没有注入Students的:
在这里插入图片描述
接下来就是调用了addSington,里面如果判断是新创建的Sington做了这样几件事情:1)移除将当前Bean放到singtonObjects中 2)将singtonFactories中的singleFactory移除
在这里插入图片描述
然后回到了ClassRoom,这个时候Student的Bean已经进行了创建,进行注入即可。同时将这个Bean从创建中进行移除。
在这里插入图片描述
这就解决了循环依赖,我的理解是通过Map存储早期的Bean,然后注入的也是早期的Bean,等到它依赖的Bean完成注入的时候,注入的早期的Bean的引用也会发生变化,类似于一个延迟加载。


网站公告

今日签到

点亮在社区的每一天
去签到