Spring循环依赖

      在 Spring 框架中,singletonObjects 是一个用于存储单例 bean 的缓存。它是一个 Map,其中键是 bean 的名称,值是对应的 bean 实例。

       Spring 默认情况下会将所有的 bean 定义为单例模式,也就是在整个 Spring 容器中,每个 bean 只会有一个实例。当一个 bean 被定义为单例模式后,Spring 容器会在初始化时立即实例化这个 bean。

      之后,每次通过容器获取这个 bean 时,都会返回同一个实例。  singletonObjects 的作用就是存储这些单例 bean 的实例,以便在需要时能够快速获取。当我们通过 ApplicationContext.getBean() 方法获取 bean 时,如果这个 bean 是单例的,那么 Spring 就会从 singletonObjects 中获取这个 bean 的实例并返回。  这种方式可以提高获取 bean 的效率,因为不需要每次都去创建新的实例,同时也保证了单例 bean 的唯一性。

	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

 

           在 Spring 框架中,earlySingletonObjects 是一个用于存储早期的单例 bean 的缓存。

          它是一个 Map,其中键是 bean 的名称,值是对应的 bean 实例。  当一个单例 bean 正在创建,但还没有完全初始化完成(例如,正在进行属性注入或者调用初始化方法)时,这个 bean 就被认为是一个早期的单例 bean。

          在这个阶段,如果有其他的 bean 依赖于这个正在创建的单例 bean,那么 Spring 就会从 earlySingletonObjects 中获取这个早期的单例 bean,并用它来满足依赖。

          earlySingletonObjects 的主要作用是解决循环依赖的问题。例如,如果 bean A 依赖于 bean B,而 bean B 又依赖于 bean A,那么在创建 bean A 的过程中,就需要先创建一个早期的 bean A,然后再去创建 bean B,最后再完成 bean A 的创建。在这个过程中,早期的 bean A 就会被存储在 earlySingletonObjects 中。

        需要注意的是,早期的单例 bean 只包含了 bean 的基本结构,还没有进行完全的初始化,因此在使用时需要特别小心,避免触发未完成初始化的操作。

	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

           在 Spring 框架中,singletonFactories 是一个用于存储单例 bean 工厂的缓存。

它是一个 Map,其中键是 bean 的名称,值是一个 ObjectFactory 对象,这个 ObjectFactory 对象可以用来创建 bean 的实例。  

         当一个单例 bean 正在创建,但还没有完全初始化完成(例如,正在进行属性注入或者调用初始化方法)时,Spring 会将一个用于生成这个 bean 的 ObjectFactory 对象存储在 singletonFactories 中。

       这样,如果在初始化过程中有其他的 bean 需要引用这个正在创建的 bean,Spring 就可以使用这个 ObjectFactory 来创建一个早期的 bean 实例。  singletonFactories 的主要作用是解决循环依赖的问题。

      例如,如果 bean A 依赖于 bean B,而 bean B 又依赖于 bean A,那么在创建 bean A 的过程中,就需要先创建一个早期的 bean A,然后再去创建 bean B,最后再完成 bean A 的创建。在这个过程中,用于创建早期 bean A 的 ObjectFactory 就会被存储在 singletonFactories 中。  需要注意的是,从 singletonFactories 中获取的是一个 ObjectFactory 对象,而不是 bean 实例本身。当我们需要获取 bean 实例时,需要调用这个 ObjectFactory 的 getObject() 方法来创建 bean 实例。

	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

		/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

@FunctionalInterface
public interface ObjectFactory<T> {

	/**
	 * Return an instance (possibly shared or independent)
	 * of the object managed by this factory.
	 * @return the resulting instance
	 * @throws BeansException in case of creation errors
	 */
	T getObject() throws BeansException;

}

	@Nullable
	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}

@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;
	}

	public boolean isSingletonCurrentlyInCreation(String beanName) {
		return this.singletonsCurrentlyInCreation.contains(beanName);
	}

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 + "'");
				}
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					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;
		}
	}

	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

Spring框架解决循环依赖的主要方式是通过三级缓存机制。  

   在Spring中,有三个重要的缓存结构:  
singletonObjects:用于存放完全初始化好的bean,也就是从容器中获取到的bean就是存放在这个Map中的bean。  
earlySingletonObjects:用于存放原始的bean对象(尚未填充属性),用于解决循环引用。  
singletonFactories:用于存放bean工厂对象,用于产生earlySingletonObjects中的对象。

 
当Spring创建bean的时候,首先会检查singletonObjects中是否存在已经创建好的bean,

如果存在则直接返回。

如果不存在,则会检查earlySingletonObjects中是否存在,如果存在则返回。

如果earlySingletonObjects中也不存在,

则会尝试从singletonFactories中获取对应的bean工厂对象,然后通过这个工厂对象创建bean。

 这样,当出现A依赖B,B依赖A的情况时,Spring在创建A的时候,发现需要B,然后去创建B,在创建B的时候发现需要A,此时A已经在earlySingletonObjects中,所以可以直接使用,从而解决了循环依赖的问题。

这段代码是Spring框架中DefaultSingletonBeanRegistry类的getSingleton方法。这个方法的主要作用是获取指定名称的单例对象。如果该单例对象还未创建,那么它会尝试创建该单例对象。  以下是这段代码的详细解释:  
Object singletonObject = this.singletonObjects.get(beanName);:

首先尝试从singletonObjects缓存中获取指定名称的单例对象。  
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { ... }

:如果在singletonObjects缓存中没有找到,并且该单例对象正在创建中(可能存在循环依赖的情况),则进入这个if语句块。  
synchronized (this.singletonObjects) { ... }:

由于可能存在多线程并发的情况,所以需要对代码块进行同步处理。  
singletonObject = this.earlySingletonObjects.get(beanName);:在同步代码块中,首先尝试从earlySingletonObjects缓存中获取单例对象。earlySingletonObjects缓存中存放的是提前暴露出来的、尚未完全初始化的单例对象,主要用于解决循环依赖的问题。  
if (singletonObject == null && allowEarlyReference) { ... }:如果在earlySingletonObjects缓存中也没有找到,并且允许提前引用单例对象,那么就进入这个if语句块。  
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);:在这个if语句块中,首先尝试从singletonFactories缓存中获取对应的单例工厂。  
if (singletonFactory != null) { ... }:如果获取到了单例工厂,那么就通过这个工厂创建单例对象,并将其添加到earlySingletonObjects缓存中,同时从singletonFactories缓存中移除对应的单例工厂。  
return singletonObject;:最后返回获取到的单例对象。如果在以上所有步骤中都没有获取到单例对象,那么这个方法将返回null。  
这段代码的主要作用是获取和创建单例对象,同时处理了单例对象的循环依赖问题。

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  // First, check if the singleton object is already created and cached.
  Object singletonObject = this.singletonObjects.get(beanName);

  // If the singleton object is not found in the cache and it is currently being created,
  // it means there might be a circular reference.
  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    synchronized (this.singletonObjects) {
      // Try to get the singleton object from the earlySingletonObjects cache.
      singletonObject = this.earlySingletonObjects.get(beanName);

      // If the singleton object is not found in the earlySingletonObjects cache and early reference is allowed,
      // it means we can create a reference to the singleton object before it is fully initialized.
      if (singletonObject == null && allowEarlyReference) {
        // Get the singleton factory from the singletonFactories cache.
        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);

        // If the singleton factory is not null, we can use it to create the singleton object.
        if (singletonFactory != null) {
          // Use the singleton factory to create the singleton object.
          singletonObject = singletonFactory.getObject();

          // Put the created singleton object into the earlySingletonObjects cache.
          this.earlySingletonObjects.put(beanName, singletonObject);

          // Remove the singleton factory from the singletonFactories cache.
          this.singletonFactories.remove(beanName);
        }
      }
    }
  }

  // Return the singleton object. If the singleton object is not found in any cache and it is not currently being created,
  // this method will return null.
  return singletonObject;
}

这段代码是Spring框架中DefaultSingletonBeanRegistry类的getSingleton方法。这个方法的主要作用是获取指定名称的单例对象。如果该单例对象还未创建,那么它会尝试创建该单例对象。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值