Spring如何解决循环依赖

Spring如何解决循环依赖

spring对循环依赖的处理有是那种情况:

  1. 构造器的循环依赖:这种依赖spring是处理不了的,直接抛出BeanCurrentlyInCreationException异常。
  2. 单例模式下的setter循环依赖:通过“三级缓存”处理循环依赖。
  3. 非单例循环依赖 :无法处理

spring如何处理第二种循环依赖

spring单例对象的初始化大略分为三步:

  • createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象
  • populateBean:填充属性,这一步主要是多Bean的依赖属性进行填充
  • initialzeBean:调用spring xml中的init方法

从上述单例bean初始化步骤可知,循环依赖主要发生在第一步、第二步。也就是构造器循环依赖和filed循环依赖。spring为了解决单例的循环依赖问题,使用了三级缓存

// DefaultSingletonBeanRegistry
	/** 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);

这三级缓存的作用分别是:

  • singletonFactories:进入实例化阶段的单例对象工厂的cache(三级缓存)
  • earlySingletonObjects:完成实例化但是尚未初始化的,提前曝光的单例对象的cache(二级缓存)
  • singletonObjects:完成初始化的单例对象的cache(一级缓存)

在创建bean的时候,会首先从cache中获取这个bean,这个换粗那就是singletonObjects。主要的调用方法是:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
    	// isSingletonCurrentlyInCreation()判断当前单例bean是否正在创建
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
                // allowEarlyReference 是否允许从singletonFactorices中通过getObject拿到对象
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
                        // 从singletonFactories中移除,并放入earlySingletonOjbects中
                        // 其实也就是从三级缓存移动到了二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

从上面三级缓存的分析,可以知道,Spring解决缓存依赖的诀窍就在于singletonFactories这个三级cache。这个cache的类型时ObjectFactory,定义如下:

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

}

这个接口在AbstractBeanFactory里实现,并在核心方法doCreateBean()引用下面的方法

	/**
	 * Add the given singleton factory for building the specified singleton
	 * if necessary.
	 * 

To be called for eager registration of singletons, e.g. to be able to * resolve circular references. * @param beanName the name of the bean * @param singletonFactory the factory for the singleton object */ 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); } } }

这段代码发生在crateBeanInstance之后,populateBean()之前,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,此时将这个对象提前曝光出来,让其他对象引用。

A的某个filed或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象。A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二部,发现自己依赖对象B,此时就尝试get(B),发现B还没有被create,所以走create流程,B在初始化的第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没有初始化完成),尝试二级缓存earlySingletonObjects(也没有),尝试三级村换singletonFactories,由于A通过ObjectFactory将自己提前曝光,所以B能够通过ObjectFactory.getObject拿到A对象(虽然还没有初始化完全,但是总比没有好吧),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到以及缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化2、3阶段,最终A也完成了初始化。进去了以及缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住了A对象完成了初始化。

你可能感兴趣的:(spring,boot,java,spring,缓存,bean,ioc)