一文详解spring循环依赖

一文详解Spring循环依赖

什么是循环依赖?

大家都知道spring的核心是一个实现了AOP的IOC容器,那么IOC容器对于bean的初始化,会遇到以下情况:当BeanA初始化时,它依赖的对象BeanB也需要执行初始化,如果BeanB里也依赖了BeanA,则又会开始执行BeanA的初始化,那么这样会无限循环,导致初始化异常如下所示。

一文详解spring循环依赖_第1张图片

Spring已经很好的解决了这个问题,这个解决方法就是三级缓存。

什么是三级缓存?

我们以上图中A、B互相依赖为例,spring为了解决循环依赖问题,做了以下步骤:

  • A通过反射创建的“初级bean”a放入到三级缓存中,再执行a的属性填充,这时发现依赖B,开启B的初始化。

  • B通过反射生成的“初级bean”b放入到三级缓存中,再执行b的属性填充,这时发现依赖A,开启A的初始化。

  • 从三级缓存中找到a,A不再创建新对象,把它移动到二级缓存中,返回a。

  • b拿到a的引用,设置到b对应的字段上,属性填充完成,将b从三级缓存暴露到一级缓存中,返回b。

  • a拿到b的引用,设置到a对应的字段上,属性填充完成,将a从二级缓存暴露到一级缓存中,返回a,A对应的实例Bean初始化完成。

    其简易时序图

一文详解spring循环依赖_第2张图片

逻辑图如下:

一文详解spring循环依赖_第3张图片

咱们再看看三级缓存的存储结构

/** Cache of singleton objects: bean name to bean instance. */
	/** 一级缓存,初始化完成的SpringBean均放置其中 */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** Cache of early singleton objects: bean name to bean instance. */
	/** 二级缓存,反射完成后,还未填充属性的初级对象但是其他对象查询过时从三级中移动到二级 */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** Cache of singleton factories: bean name to ObjectFactory. */
	/** 三级缓存,反射完成后,还未填充属性的初级对象放置其中 */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

为什么三级缓存earlySingletonObjects和二级缓存singletonFactories的初始容量16,而一级缓存容量为256呢?笔者认为因为二级、三级仅仅是在处理依赖时会使用到,这种多重循环依赖的情况在实际项目中应该是少数,所以不用使用太大的空间。而最终spring实例化完成的bean会放置在一级缓存中,所以默认容量会调大一些,毕竟spring有很多自身的bean也是放置在这里面的,比如systemEnvironment、systemProperties、messageSource、applicationEventMulticaster等。

spring的源码阅读

  1. 当单例对象不存在时,会通过org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory)方法来获取单例对象。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   
		/** 省略部分代码 */
		synchronized (this.singletonObjects) {
   
			Object singletonObject = this.singletonObjects.get(beanName);
			// 在一级缓存singletonObjects中拿到为空 
			if (singletonObject == null) {
   
				/** 省略状态检查部分代码 */
				
				
				boolean newSingleton = false;
				
				try {
   
					// 传进来的调用,lamda表达式使用
					singletonObject = singletonFactory.getObject();
					// *********重要*********:singletonFactory.getObject()执行完毕,标记此类已经初始化完成
					// bean初始化完成,标记为新的单例对象
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
   
					/** 省略部分代码 */
				}
				finally {
   
					if (recordSuppressedExceptions) {
   
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				// 如果是新的单例对象,暴露到一级缓存中
				if (newSingleton) {
   
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}
	
	/**
	 * Add the given singleton object to the singleton cache of this factory.
	 * 

To be called for eager registration of singletons. * @param beanName the name of the bean * @param singletonObject the singleton object */ 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); } }

  1. 上面代码中的singletonFactory.getObject() 无疑是执行创建的关键代码:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])方法

/**
	 * Central method of this class: creates a bean instance,
	 * populates the bean instance, applies post-processors, etc.
	 * @see #doCreateBean
	 */
	@Override
	protected Object createBean(String beanName

你可能感兴趣的:(Spring全家桶)