spring 如何解决循环依赖的

一. spring启动过程中循环依赖相关的流程

image.png

二. 过程分析

我们假设有两个Bean, beanName分别是A和B,其中A被切面C切中。
源码入口

//参考<> 3. Bean实例化入口
//入口refresh--> finishBeanFactoryInitialization-->
//DefaultListableBeanFactory preInstantiateSingletons()
for (String beanName : beanNames) {
        //循环遍历所有beanNames,我们假设A先遍历到
        //非抽象&单例的&非懒加载
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            ... ... ... ...
            getBean(beanName);
            ... ... ... ...
        }
}

---
       @Override
    public Object getBean(String name) throws BeansException {
        //真正的获取bean的逻辑
        return doGetBean(name, null, null, false);
    }

2.1 从缓存中获取A

singletonObjects为一级缓存,里边存放已完整创建的单例Bean。 这里获取A时,一级缓存不存在,且isSingletonCurrentlyInCreation为false,此时正在创建Bean集合中没有bean A。所有没有获取到缓存。

//doGetBean方法
Object sharedInstance = getSingleton(beanName);
      //实现allowEarlyReference=true
     @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        /**
         * 第一步:我们尝试去一级缓存(单例缓存池中去获取对象,一般情况从该map中获取的对象是直接可以使用的)
         * IOC容器初始化加载单实例bean的时候第一次进来的时候 该map中一般返回空
         */
        Object singletonObject = this.singletonObjects.get(beanName);
        /**
         * 若在第一级缓存中没有获取到对象,并且singletonsCurrentlyInCreation这个list包含该beanName
         * IOC容器初始化加载单实例bean的时候第一次进来的时候 该list中一般返回空,但是循环依赖的时候可以满足该条件
         */
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                /**
                 * 尝试去二级缓存中获取对象(二级缓存中的对象是一个早期对象)
                 * 何为早期对象:就是bean刚刚调用了构造方法,还来不及给bean的属性进行赋值的对象(纯净态)
                 * 就是早期对象
                 */
                singletonObject = this.earlySingletonObjects.get(beanName);
                /**
                 * 二级缓存中也没有获取到对象,allowEarlyReference为true(参数是有上一个方法传递进来的true)
                 */
                if (singletonObject == null && allowEarlyReference) {
                    /**
                     * 直接从三级缓存中获取 ObjectFactory对象 这个对接就是用来解决循环依赖的关键所在
                     * 在ioc后期的过程中,当bean调用了构造方法的时候,把早期对象包裹成一个ObjectFactory
                     * 暴露到三级缓存中
                     */
                    ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
                    //从三级缓存中获取到对象不为空
                    if (singletonFactory != null) {
                        /**
                         * 在这里通过暴露的ObjectFactory 包装对象中,通过调用他的getObject()来获取我们的早期对象
                         * 在这个环节中会调用到 getEarlyBeanReference()来进行后置处理
                         */
                        singletonObject = singletonFactory.getObject();
                        //把早期对象放置在二级缓存,
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        //ObjectFactory 包装对象从三级缓存中删除掉
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

2.2 设置正在创建

缓存中没有,开始创建,先通过beforeSingletonCreation方法,将beanA放入正在创建Bean的集合中

                ////doGetBean方法
                //创建单例bean
                if (mbd.isSingleton()) {
                    //把beanName 和一个singletonFactory 并且传入一个回调对象用于回调
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            //进入创建bean的逻辑
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            //创建bean的过程中发生异常,需要销毁关于当前bean的所有信息
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

//DefaultSingletonBeanRegistry.getSingleton
    public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
              ... ... ... ...
              beforeSingletonCreation(beanName);
              ... ... ... ...
              singletonObject = singletonFactory.getObject();
                newSingleton = true;
                ... ... ... ...
              if (newSingleton) {
            // <5> 加入缓存中
            addSingleton(beanName, singletonObject);
        }    
              ... ... ... ...
}
protected void beforeSingletonCreation(String beanName) {
        //若singletonsCurrentlyInCreation 没添加成功
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
}
/**
     * 把对象加入到单例缓存池中(所谓的一级缓存 并且考虑循环依赖和正常情况下,移除二三级缓存)
     * @param beanName bean的名称
     * @param singletonObject 创建出来的单实例bean
     */
    protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            //加入到单例缓存池中
            this.singletonObjects.put(beanName, singletonObject);
            //从三级缓存中移除(针对的不是处理循环依赖的)
            this.singletonFactories.remove(beanName);
            //从二级缓存中移除(循环依赖的时候 早期对象存在于二级缓存)
            this.earlySingletonObjects.remove(beanName);
            //用来记录保存已经处理的bean
            this.registeredSingletons.add(beanName);
        }
    }

在创建BeanA之前,先检查mbd.getDependsOn();是否为空,这里的dependOn非循环依赖的依赖,而是 @DependsOn(value = {"dependsA"}) 手动添加的依赖。

2.3 实例化A

上一步源码中getSingleton是传入一个回调函数,然后再singletonFactory.getObject()时执行。即执行createBean(beanName, mbd, args);

//AbstractAutowireCapableBeanFactory.createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {
                // 解析类
                ... ... ... ...
                Object beanInstance = doCreateBean(beanName, mbdToUse, args);
                 ... ... ... ...
               
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {
                 ... ... ... ...
                 //实例化
                instanceWrapper = createBeanInstance(beanName, mbd, args);
                final Object bean = instanceWrapper.getWrappedInstance();
                 ... ... ... ...
               
}

2.4 放入三级缓存

上一步完成实例化后。接着判断是否需要暴露早期的Bean实例,此时条件满足
earlySingletonExposure=true, 执行addSingletonFactory方法,但是这里没有直接将早期的Bean放入缓存,放入的是一个回调。

 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
  if (earlySingletonExposure) {
    //把我们的早期对象包装成一个singletonFactory对象 该对象提供了一个getObject方法,该方法内部调用getEarlyBeanReference方法
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        //同步加锁
        synchronized (this.singletonObjects) {
            //单例缓存池中没有包含当前的bean
            if (!this.singletonObjects.containsKey(beanName)) {
                //加入到三级缓存中,,,,,暴露早期对象用于解决循环依赖
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    }
        

2.4 属性注入B

执行完三级缓存set逻辑,接着开始准备属性注入. 由于我们假设A依赖B,所有这里会执行BeanB的获取。即回到和A相同的开始——getBean

populateBean(beanName, mbd, instanceWrapper);
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
     ... ... ... ...
      //获取bean定义的属性
      PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
       ... ... ... ...
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      //按照name注入
      autowireByName(beanName, mbd, bw, newPvs);
      //按照type注入
      autowireByType(beanName, mbd, bw, newPvs
      ... ... ... ...
    }  
protected void autowireByName(
            String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
            ... ... ... ...
            if (containsBean(propertyName)) {
                    Object bean = getBean(propertyName);
            }
            ... ... ... ...

}

2.5 BeanB属性注入A

遵循前边相同的流程,getBean 获取B,最终执行B的属性注入,再次getBeanA

2.6 第二次获取BeanA

我们在两次获取BeanA中间,2.2 设置正在创建BeanA,且三级缓存中放入了BeanA。

2.7 第二次从缓存中获取A

这一次,我们从一级和二级中都没有获取到BeanA,但是我们从三级缓存中获取到了一个回调函数—— getEarlyBeanReference,然后我们在获取缓存代码中执行 singletonObject = singletonFactory.getObject(),执行回调函数。

2.8 执行三级缓存回调

直接查询容器中有没有InstantiationAwareBeanPostProcessors的后置处理器。我们在文章开头假设中,假设A被切面C切中,即A需要被动态代理。

恰好AbstractAutoProxyCreator动态代理创建类实现了SmartInstantiationAwareBeanPostProcessor接口,实现了getEarlyBeanReference方法。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        //判读我们容器中是否有InstantiationAwareBeanPostProcessors类型的后置处理器
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            //获取我们所有的后置处理器
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                //判断我们的后置处理器是不是实现了SmartInstantiationAwareBeanPostProcessor接口
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    //进行强制转换
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    //挨个调用SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
        ... ... ... ...
        @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        this.earlyProxyReferences.put(cacheKey, bean);
        return wrapIfNecessary(bean, beanName, cacheKey);
    }
        ... ... ... ...
}

2.9 B初始化

A 生成代理对象后放入二级缓存并返回。 B执行属性注入,开始初始化。

exposedObject = initializeBean(beanName, exposedObject, mbd);
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
      ... ... ... ...
      //若我们的bean实现了XXXAware接口进行方法的回调    
      invokeAwareMethods(beanName, bean);
       ... ... ... ...
       //调用我们的bean的后置处理器的postProcessorsBeforeInitialization方法  
//@PostConstruct注解的方法
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
      ... ... ... ...
      //调用初始化方法
      invokeInitMethods(beanName, wrappedBean, mbd);
     ... ... ... ...
     //调用我们bean的后置处理器的PostProcessorsAfterInitialization方法
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

}
@Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {

        Object result = existingBean;
        //获取我们容器中的所有的bean的后置处理器
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            /**
             * 在这里是后置处理器的【第九次调用】 aop和事务都会在这里生存代理对象
             *
             * 【很重要】
             * 我们AOP @EnableAspectJAutoProxy 为我们容器中导入了 AnnotationAwareAspectJAutoProxyCreator
             * 我们事务注解@EnableTransactionManagement 为我们的容器导入了 InfrastructureAdvisorAutoProxyCreator
             * 都是实现了我们的 BeanPostProcessor接口,InstantiationAwareBeanPostProcessor,
             * 在这里实现的是BeanPostProcessor接口的postProcessAfterInitialization来生成我们的代理对象
             */
            Object current = processor.postProcessAfterInitialization(result, beanName);
            //若只有有一个返回null 那么直接返回原始的
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

在B完成初始化后,最后执行了applyBeanPostProcessorsAfterInitialization,动态代理处理类也实现了该方法。也就是说,这里也可能返回代理类。

2.10 A完成初始化

B完成初始化后返回给A的属性注入,A完成属性注入后,接着完成初始化并返回。注意:由于A之前已经生成代理类,这里不会再重复创建。

@Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
        if (bean != null) {
            //获取缓存key
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            // 之前循环依赖创建的动态代理 如果是现在的bean 就不再创建,并且移除
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                // 该方法将会返回动态代理实例
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

2.11 A放入一级缓存

中间B也放入了一级缓存。再这里一起讲。 再2.2中,我们getSingleton方法中执行了回调方法完成Bean的创建,再执行完回调后,其实还有逻辑。

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
              ... ... ... ...
              beforeSingletonCreation(beanName);
              ... ... ... ...
              singletonObject = singletonFactory.getObject();
                newSingleton = true;
                ... ... ... ...
              if (newSingleton) {
            // <5> 加入缓存中
            addSingleton(beanName, singletonObject);
        }    

singletonFactory.getObject()执行回调,设置newSingleton = true,最后执行 addSingleton(beanName, singletonObject);

protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            //加入到单例缓存池中
            this.singletonObjects.put(beanName, singletonObject);
            //从三级缓存中移除(针对的不是处理循环依赖的)
            this.singletonFactories.remove(beanName);
            //从二级缓存中移除(循环依赖的时候 早期对象存在于二级缓存)
            this.earlySingletonObjects.remove(beanName);
            //用来记录保存已经处理的bean
            this.registeredSingletons.add(beanName);
        }
    }

三. 常见问题

3.1. 二级缓存能不能解决循环依赖,为什么需要三级缓存

二级缓存可以解决循环依赖,在实例化后,属性注入和初始化前,将实例化后的Bean放入二级缓存池就可以。那为什么需要三级缓存呢?

网上很多答案是因为代理的原因,确实是其中重要的原因。但个人觉得还不够准确,因为二级缓存也可以直接放代理类进去。需要三级缓存个人比较赞成这个观点:

Bean的创建流程首先应该完成主体流程-即没有循环依赖的,没有代理的正常Bean创建流程。 在主体流程外提供扩展功能以满足其他需求。 单一职责的原则,循环依赖的解决放入专门解决循环依赖的地方——缓存,而不是在实例化后为了解决循环依赖+代理的问题,直接把代理生成的位置放在实例化后。

3.2. spring有没有解决构造函数的循环依赖

没有。 构造函数在实例化时调用。spring没有干预。

3.3.spring有没有解决多例下的循环依赖

没有。 多例没有缓存

你可能感兴趣的:(spring 如何解决循环依赖的)