跳槽那些事儿@面试问你Spring如何解决循环依赖的时候,不要一脸懵逼了!( 二 )


2、源码讲解 对于Spring处理循环依赖问题的方式 , 我们这里通过上面的流程图其实很容易就可以理解 , 需要注意的一个点就是 , Spring是如何标记开始生成的A对象是一个半成品 , 并且是如何保存A对象的 。 这里的标记工作Spring是使用ApplicationContext的属性SetsingletonsCurrentlyInCreation来保存的 , 而半成品的A对象则是通过Map singletonFactories来保存的 , 这里的ObjectFactory是一个工厂对象 , 可通过调用其getObject()方法来获取目标对象 。 在AbstractBeanFactory.doGetBean()方法中获取对象的方法如下:
protectedT doGetBean(final String name, @Nullable final Class requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {// 尝试通过bean名称获取目标bean对象 , 比如这里的A对象Object sharedInstance = getSingleton(beanName);// 我们这里的目标对象都是单例的if (mbd.isSingleton()) {// 这里就尝试创建目标对象 , 第二个参数传的就是一个ObjectFactory类型的对象 , 这里是使用Java8的lamada// 表达式书写的 , 只要上面的getSingleton()方法返回值为空 , 则会调用这里的getSingleton()方法来创建// 目标对象sharedInstance = getSingleton(beanName, () -> {try {// 尝试创建目标对象return createBean(beanName, mbd, args);} catch (BeansException ex) {throw ex;}});}return (T) bean;} 这里的doGetBean()方法是非常关键的一个方法(中间省略了其他代码) , 上面也主要有两个步骤 , 第一个步骤的getSingleton()方法的作用是尝试从缓存中获取目标对象 , 如果没有获取到 , 则尝试获取半成品的目标对象;如果第一个步骤没有获取到目标对象的实例 , 那么就进入第二个步骤 , 第二个步骤的getSingleton()方法的作用是尝试创建目标对象 , 并且为该对象注入其所依赖的属性 。
这里其实就是主干逻辑 , 我们前面图中已经标明 , 在整个过程中会调用三次doGetBean()方法 , 第一次调用的时候会尝试获取A对象实例 , 此时走的是第一个getSingleton()方法 , 由于没有已经创建的A对象的成品或半成品 , 因而这里得到的是null , 然后就会调用第二个getSingleton()方法 , 创建A对象的实例 , 然后递归的调用doGetBean()方法 , 尝试获取B对象的实例以注入到A对象中 , 此时由于Spring容器中也没有B对象的成品或半成品 , 因而还是会走到第二个getSingleton()方法 , 在该方法中创建B对象的实例 , 创建完成之后 , 尝试获取其所依赖的A的实例作为其属性 , 因而还是会递归的调用doGetBean()方法 , 此时需要注意的是 , 在前面由于已经有了一个半成品的A对象的实例 , 因而这个时候 , 再尝试获取A对象的实例的时候 , 会走第一个getSingleton()方法 , 在该方法中会得到一个半成品的A对象的实例 。 然后将该实例返回 , 并且将其注入到B对象的属性a中 , 此时B对象实例化完成 。 然后将实例化完成的B对象递归的返回 , 此时就会将该实例注入到A对象中 , 这样就得到了一个成品的A对象 。 我们这里可以阅读上面的第一个getSingleton()方法:
@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// 尝试从缓存中获取成品的目标对象 , 如果存在 , 则直接返回Object singletonObject = this.singletonObjects.get(beanName);// 如果缓存中不存在目标对象 , 则判断当前对象是否已经处于创建过程中 , 在前面的讲解中 , 第一次尝试获取A对象// 的实例之后 , 就会将A对象标记为正在创建中 , 因而最后再尝试获取A对象的时候 , 这里的if判断就会为trueif (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {// 这里的singletonFactories是一个Map , 其key是bean的名称 , 而值是一个ObjectFactory类型的// 对象 , 这里对于A和B而言 , 调用图其getObject()方法返回的就是A和B对象的实例 , 无论是否是半成品ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 获取目标对象的实例singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}


推荐阅读