Spring如何解决循环依赖问题?

getSingleton(String beanName)

在Spring的doGetBean()方法中的第一次调用getSingleton方法(也就是getSingleton(String beanName)方法)中,反映了Spring中针对循环依赖的解决思想。

当Spring容器初始化时,对于每一个声明为单例的Bean,Spring都会创建一个对应的ObjectFactory并将其存储在singletonFactories映射中。在这个映射中,beanName作为键,对应的ObjectFactory作为值。因此,当需要获取一个单例Bean的实例时,Spring会首先尝试从singletonObjects映射中获取该实例。如果该实例不存在,并且允许早期引用(allowEarlyReference为true),那么Spring会从earlySingletonObjects映射中获取该实例。如果仍不存在,Spring会从singletonFactories映射中获取对应的ObjectFactory,并调用其getObject()方法来创建并返回该Bean的实例。

这个ObjectFactory和earlySingletonObjects就是解决循环依赖问题的关键!

// Bean实例的缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);


protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // 从缓存中获取
   Object singletonObject = this.singletonObjects.get(beanName);
   // 若缓存内不存在且当前正在创建该单例Bean
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         // 从早期缓存中获取单例实例
         singletonObject = this.earlySingletonObjects.get(beanName);
         // 若早期缓存中不存在且允许早期引用
         if (singletonObject == null && allowEarlyReference) {
            // 获取对应的ObjectFactory
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               // 获取该ObjectFactory对应的实例
               singletonObject = singletonFactory.getObject();
               // 填充早期缓存
               this.earlySingletonObjects.put(beanName, singletonObject);
               // 删除对应的ObjectFactory
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

在这个getSingleton方法中,Spring使用了几个关键的策略和技术来解决循环依赖的问题。

  1. 三级缓存机制:Spring使用了三级缓存机制,即singletonObjectsearlySingletonObjectssingletonFactories。这三个Map结构用于存储不同阶段的单例Bean。
    • singletonObjects:存储完全初始化好的Bean。
    • earlySingletonObjects:存储Bean的早期引用,也就是说Bean已经被实例化了,但是还没进行属性填充和初始化方法。
    • singletonFactories:存储创建Bean的工厂对象,也就是ObjectFactory。
  2. 检查当前Bean是否在创建中isSingletonCurrentlyInCreation(beanName)方法用于检查当前Bean是否正在被创建。如果返回true,说明存在循环依赖。
  3. 同步代码块:当检测到循环依赖时,Spring使用了同步代码块来确保线程安全。这避免了在多线程环境下可能出现的并发问题。
  4. singletonFactories中获取ObjectFactory:如果当前Bean正在创建中并且允许早期引用,Spring会从singletonFactories中获取该Bean的ObjectFactory。
  5. 通过ObjectFactory创建Bean的早期引用:然后调用ObjectFactory的getObject()方法来创建一个该Bean的早期引用,并将其放入earlySingletonObjects缓存中。同时从singletonFactories中移除该ObjectFactory,确保每个Bean只被创建一次。
  6. 解决循环依赖:通过这种机制,即使Bean还没有完全初始化完成,其他依赖于它的Bean也可以通过earlySingletonObjects获取到它的早期引用,从而解决了循环依赖的问题。

总结来说,Spring通过三级缓存机制、同步代码块和ObjectFactory的配合使用,巧妙地解决了循环依赖的问题。这确保了每个Bean只被创建一次,并且在解决依赖关系时线程安全。

你可能感兴趣的:(Spring,spring,java,后端)