循环依赖其实就是循环引用,也就是两个或者两个以上的 Bean 互相持有对方,最终形成闭环。
比如 A 依赖于 B,B 依赖于 C,C 又依赖于 A。
注意:这里不是函数的循环调用,是对象的相互依赖关系。
循环调用其实就是一个死循环,除非有终结条件。
Spring 中循环依赖场景有:
其中,构造器的循环依赖问题无法解决,只能拋出 BeanCurrentlyInCreationException 异常,在解决
属性循环依赖时,spring 采用的是提前暴露对象的方法。
不支持处理条件的有:
对于 prototype 原型 bean 的初始化过程中不论是通过构造器参数循环依赖还是通过 setXxx 方法产生循环依赖,Spring 都会直接报错处理。
查看源码进行分析。
AbstractBeanFactory.doGetBean() 方法:
// 如果是 prototype 类型且开启允许循环依赖,则抛出异常 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
AbstractBeanFactory#isPrototypeCurrentlyInCreation
protected boolean isPrototypeCurrentlyInCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))); }
在获取 bean 之前如果这个原型 bean 正在被创建则直接抛出异常。
原型 bean 在创建之前会进行标记这个 beanName 正在被创建,等创建结束之后会删除标记。
AbstractBeanFactory#doGetBean
try { // 创建原型 bean 之前添加标记 beforePrototypeCreation(beanName); // 创建原型 bean prototypeInstance = createBean(beanName, mbd, args); } finally { // 创建原型 bean 之后删除标记 afterPrototypeCreation(beanName); }
1)单例 bean 通过 setXxx 或者 @Autowired 进行循环依赖。
2)Spring 容器初始化 ClassA 通过构造器初始化对象后提前暴露到 Spring 容器。
AbstractAutowireCapableBeanFactory#doCreateBean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } // 将初始化后的对象提前以 ObjectFactory 对象注入到容器中 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); }
3)ClassA 调用 setClassB 方法,Spring 首先尝试从容器中获取 ClassB,此时 ClassB 不存在 Spring 容器中。
4)Spring 容器初始化 ClassB,同时也会将 ClassB 提前暴露到 Spring 容器中。
5)ClassB 调用 setClassA 方法,Spring 从容器中获取 ClassA ,因为第一步中已经提前暴露了 ClassA,因此可以获取到 ClassA 实例。
6)ClassA 通过 Spring 容器获取到 ClassB,完成了对象初始化操作。
7)这样 ClassA 和 ClassB 都完成了对象初始化操作,解决了循环依赖问题。
提示:如果有还不熟悉 Spring IoC 源码的朋友请优先查看 Spring IoC 源码刨析 。
三级缓存主要是在类 DefaultSingletonBeanRegistry 当中。
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { /** Cache of singleton objects: bean name to bean instance. */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); }
applicationContext.xml
<!--循环依赖问题--> <bean id="lagouBean" class="com.lagou.edu.LagouBean"> <property name="ItBean" ref="itBean"/> </bean> <bean id="itBean" class="com.lagou.edu.ItBean"> <property name="LagouBean" ref="lagouBean"/> </bean>
实体类略。
step1:先查看获取 lagouBean 实例化对象时,
AbstractBeanFactory#doGetBean 方法中。
// 创建单例 bean sharedInstance = getSingleton(beanName, () -> { try { // 创建 bean return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } });
step2:lagouBean 对象实例化创建。
AbstractAutowireCapableBeanFactory#doCreateBean
if (instanceWrapper == null) { // 创建 Bean 实例,仅仅调用构造方法,但是尚未设置属性 instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance();
step3:合成工厂对象 lagouBeanFactory,并存储在三级缓存当中。
继续在 AbstractAutowireCapableBeanFactory#doCreateBean 当中。
// 将初始化后的对象提前以 ObjectFactory 对象注入到容器中 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
DefaultSingletonBeanRegistry#addSingletonFactory
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { // 存储三级缓存 this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
step4:lagouBean 填充属性 itBean。
继续在 AbstractAutowireCapableBeanFactory#doCreateBean 当中。
// Bean属性填充 populateBean(beanName, mbd, instanceWrapper);
之后跟踪到调用 AbstractBeanFactory.getBean 方法来获取 itBean对象,
具体跟踪路径是:
AbstractAutowireCapableBeanFactory#applyPropertyValues -->
AbstractAutowireCapableBeanFactory#applyPropertyValues -->
BeanDefinitionValueResolver#resolveValueIfNecessary -->
BeanDefinitionValueResolver#resolveReference -->
AbstractBeanFactory#getBean
step5:与 step1、step2 、 step3 和 step4 步骤相同,只是目标对象是 itBean。
step6:itBean 在填充属性 lagouBean 过程中,会在三级缓存当中获取到 lagouBeanFactory,并用其获取 lagouBean 对象,存储在二级缓存当中,删除三级缓存。
在 AbstractBeanFactory#doGetBean 方法当中:
// 单纯理解尝试从缓存中获取 bean Object sharedInstance = getSingleton(beanName);
DefaultSingletonBeanRegistry#getSingleton
@Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 首先在一级缓存当中获取对象 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 在二级缓存中获取对象 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // 在三级缓存中获取工厂对象 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 通过工厂对象获取目标对象,删除三级缓存,保存在二级缓存当中 singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
step7:回到 step5 最后,itBean 填充属性 lagouBean 完成。
再回到 itBean 对象的 step1,完成后的 itBean 实例化对象进入了 getSingleton 方法当中。
获取 itBean 对象,存入一级缓存,删除三级缓存。
DefaultSingletonBeanRegistry#getSingleton
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 是否正在销毁,异常 if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } // 验证完要真正开始创建对象,先标识该 bean 正在被创建,因为 spingbean 创建过程复杂,步骤很多,需要标识 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 传进来的调用,lamda 表达式使用 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } }
DefaultSingletonBeanRegistry#addSingleton
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { // 存入一级缓存,删除二级缓存 与 三级缓存 this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
step8:最后回到 lagouBean 的 step1 步骤,再次带着 完成后的 lagouBean 实例化对象进入 getSingleton 方法当中。
获取对象,存入一级缓存,删除二级缓存。
结束。
文章内容输出来源:拉勾教育Java高薪训练营;