Spring循环依赖--源码分析

Spring的循环依赖对我来说一直是一个迷,在通过长时间的学习,终于解开了这一面纱,以下就是我理解整个循环依赖的处理过程。我从Spring容器初始化开始说起,当然着重点主要在循环依赖的过程,通过博客可以让自己理解更加深刻,也希望对大家学习能有所帮助。整个过程这里总共分为11步:

1、Spring容器开始初始化,以AnnotationConfigApplicationContext为例,通过调用AnnotationConfigApplicationContext的配置类构造方法

org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(java.lang.Class<?>...)

2、构造方法内部会调用其默认构造方法,默认构造方法会调用其父类默认构造方法org.springframework.context.support.GenericApplicationContext#GenericApplicationContext(),初始化属性bean工厂beanFactory = new DefaultListableBeanFactory();DefaultListableBeanFactory类里有很多重要的属性,如beanDefinitionMap是保存定义bean的对象,beanDefinitionNames是已经放入beanDefinitionMap内的beanName集合,以及单例池等等;父类构造完毕,会初始化两个对象

  • AnnotatedBeanDefinitionReader用于读取BeanDefinition信息
  • ClassPathBeanDefinitionScanner用于扫描一个类/包 并且将其转换成BeanDefinition
org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext()

3、调用注册方法,将配置类注册到beanFactory的beanDefinitionMap内

org.springframework.context.annotation.AnnotationConfigApplicationContext#register

4、准备好bean工厂,实例化对象,bean的实例化都在这个方法里,这个方法总共调用了12个方法,这里主要关注倒数第二个方法finishBeanFactoryInitialization去实例化非懒加载的单例对象

org.springframework.context.support.AbstractApplicationContext#refresh

5、开始实例化非懒加载的单例对象

org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization -->

org.springframework.beans.factory.config.ConfigurableListableBeanFactory#preInstantiateSingletons

6、通过调用getBean方法获取及实例化对象,从这里开始实例化非Spring内部的非懒加载的单例对象;

这里面包含了循环依赖的处理,从这里到结束主要记录循环依赖的调用链,大家可以对应每一个方法及模块看代码;

这里以@Autowired注入为例,如A类依赖B类,同时B类页依赖A类(A->B->A),首先通过getBean实例化A类

org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)

7、在这个方法里会先调用这个方法尝试从缓存获取A对象,如果没有则会直接创建A对象

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

	/**
	 * 这里是从缓存取beanName对应的单例对象,如单例池内的对象、正在创建中的对象
	 */
	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		if (logger.isTraceEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	else {
		// Fail if we're already creating this bean instance:
		// We're assumably within a circular reference.
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		// Check if bean definition exists in this factory.
		BeanFactory parentBeanFactory = getParentBeanFactory();
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// Not found -> check parent.
			String nameToLookup = originalBeanName(name);
			if (parentBeanFactory instanceof AbstractBeanFactory) {
				return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
						nameToLookup, requiredType, args, typeCheckOnly);
			}
			else if (args != null) {
				// Delegation to parent with explicit args.
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else if (requiredType != null) {
				// No args -> delegate to standard getBean method.
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
			else {
				return (T) parentBeanFactory.getBean(nameToLookup);
			}
		}

		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}

		try {
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			// Guarantee initialization of beans that the current bean depends on.
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (String dep : dependsOn) {
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					registerDependentBean(dep, beanName);
					try {
						getBean(dep);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}

			// Create bean instance.
			if (mbd.isSingleton()) {
				/**
				 * 这里直接创建对象
				 */
				sharedInstance = getSingleton(beanName, () -> {
					try {
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						// Explicitly remove instance from singleton cache: It might have been put there
						// eagerly by the creation process, to allow for circular reference resolution.
						// Also remove any beans that received a temporary reference to the bean.
						destroySingleton(beanName);
						throw ex;
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}

			else if (mbd.isPrototype()) {
				// It's a prototype -> create a new instance.
				Object prototypeInstance = null;
				try {
					beforePrototypeCreation(beanName);
					prototypeInstance = createBean(beanName, mbd, args);
				}
				finally {
					afterPrototypeCreation(beanName);
				}
				bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
			}

			else {
				String scopeName = mbd.getScope();
				final Scope scope = this.scopes.get(scopeName);
				if (scope == null) {
					throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
				}
				try {
					Object scopedInstance = scope.get(beanName, () -> {
						beforePrototypeCreation(beanName);
						try {
							return createBean(beanName, mbd, args);
						}
						finally {
							afterPrototypeCreation(beanName);
						}
					});
					bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
				}
				catch (IllegalStateException ex) {
					throw new BeanCreationException(beanName,
							"Scope '" + scopeName + "' is not active for the current thread; consider " +
							"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
							ex);
				}
			}
		}
		catch (BeansException ex) {
			cleanupAfterBeanCreationFailure(beanName);
			throw ex;
		}
	}

	// Check if required type matches the type of the actual bean instance.
	if (requiredType != null && !requiredType.isInstance(bean)) {
		try {
			T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
			if (convertedBean == null) {
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
			return convertedBean;
		}
		catch (TypeMismatchException ex) {
			if (logger.isTraceEnabled()) {
				logger.trace("Failed to convert bean '" + name + "' to required type '" +
						ClassUtils.getQualifiedName(requiredType) + "'", ex);
			}
			throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
		}
	}
	return (T) bean;
}

这个方法里会调用两个getSingleton方法(第11行和第86行):

  • org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)
  • org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)

第一个是从缓存获取A对应的对象,第二个是直接创建A对象(因为对象没有在缓存,说明还没开始实例化)

8、首先尝试从缓存中获取A对象

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//先到一级缓存singletonObjects拿A,这里都是已经实例化完成的对象,在创建中的对象不会得到
	Object singletonObject = this.singletonObjects.get(beanName);
	//如果一级缓存拿不到,因为二级缓存和三级缓存缓存的对象的状态都是处于正在创建中,
	//所以这里会通过方法isSingletonCurrentlyInCreation(beanName)检查beanName是否正在创建中,
	//然后才会尝试去二级和三级缓存拿以提高效率;
	//如果beanName对应的对象正在创建中,再尝试从二级缓存earlySingletonObjects中拿,即提前曝光的正在创建中的对象
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				//如果二级缓存依然没有拿到,这时候会校验allowEarlyReference是否应该提前曝光对象(是否允许从singletonFactories中通过getObject拿到对象)
				//如果是true则会从singletonFactories获取
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					singletonObject = singletonFactory.getObject();
					//这里是将对象从三级缓存移除,加入到二级缓存内
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

这里缓存包含了三级缓存

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

/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

四个变量的含义与关系

  • 一级缓存:singletonObjects指已经被实例化完成的单例对象的缓存
  • 二级缓存:earlySingletonObjects指正在创建中的对象(已经被实例化,但是还没有填充属性),并且已经提前曝光的单例对象的缓存,这里的曝光是指已经被拿出来使用过一次了
  • 三级缓存:singletonFactories指单例对象工厂的缓存,这里是指对象正在创建中(已经被实例化,但是还没有填充属性),但是还没有曝光,因为还没有拿出来使用过,一旦曝光就会将其移除,加入到二级缓存
  • 被注册的单例对象:这里保存的是已经被注册的单例对象,包括已经创建完成的和正在创建中的对象(已经被实例化,但是还没有填充属性),由此可以知道这个变量报错的应该是前三个变量的总和。通过方法addSingleton和addSingletonFactory两个方法可以推断出来。
  • 关系:singletonObjects与singletonFactories,earlySingletonObjects三者应该是互斥的,一个bean如果在其中任意一个变量中,就不会存在在另一变量中,这三个变量用于记录一个bean的不同状态。存在三个缓存中的对象,都会放在registeredSingletons中,表示已经注册了

所以,Spring的循环依赖,只要是在这里实现的,通过三级缓存完美的解决的循环依赖的问题。

9、因为A还没有创建,所以缓存没有获取到,再直接创建单例A对象。

这里需要注意的是,在调用方法doCreateBean时,会将创建的对象放入到三级缓存singletonFactories中(可以肯定是在这里放入的,但是其实这里我也有疑问,是怎么放进去的???)。

//第二次调用的方法,里面会直接创建对象
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)  -->

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

//通过调用构造方法(默认)创建A,同时这里会将创建的对象放入到三级缓存singletonFactories中
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean 

10、A对象创建完成之后Spring会通过后置处理器AutowiredAnnotationBeanPostProcessor为其自动注入属性B对象,这里会根据B的beanName调用getBean方法获取B的对象,然后会再次进入doGetBean方法内,类似与第8步,在这个方法里会先调用这个方法尝试从缓存获取B对象,如果没有则会直接创建B对象。很显然,这里同样是无法从三个级别缓存中获取到B对象的,因为其还没开始创建。所以这里同样会触发直接创建B对象。调用链如下:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean  -->

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties  -->

org.springframework.beans.factory.annotation.InjectionMetadata#inject  -->

org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement#inject  -->

org.springframework.beans.factory.config.AutowireCapableBeanFactory#resolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, java.lang.String, java.util.Set<java.lang.String>, org.springframework.beans.TypeConverter) -->

org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency  -->

//在这里会根据B的beanName调用getBean方法获取B的对象,以便注入到A对象的属性中
org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate  -->

org.springframework.beans.factory.BeanFactory#getBean(java.lang.String)  -->

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean  -->

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)  -->

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)  -->

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

//B对象在这里会创建完成,但是还没有为其属性注入值
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean  -->

11、同样的,B对象创建完成之后Spring会通过后置处理器AutowiredAnnotationBeanPostProcessor为其自动注入属性A对象,这里会根据A的beanName调用getBean方法获取A的对象,然后会再次进入doGetBean方法内,类似与第8、10步,在这个方法里会先调用这个方法尝试从缓存获取A对象,如果没有则会直接创建A对象。

注意,重要的地方就在这里,这里会先从一级缓存singletonObjects中取A对象,因为A还没有实例化完毕(等待获取B对象注入),所以这里无法取到;再检查A对象是否处于正在创建中的状态,很明显A还没实例化完毕,也就是说A是处于正在创建中状态的,所以程序会继续到二级缓存获earlySingletonObjects中取,因为现在A还没有提前曝光,所以二级缓存也取不到,这个时候会校验是否允许提前曝光A(前面调用时传的true),所以会到三级缓存singletonFactories中取,因为A在创建的时候已经将其放入这里,所以三级缓存可以成功的获取到已经创建完毕的A对象(属性还没有注入,因为在等待B对象的实例化完成),然后将A对象从三级缓存移除,放入到二级缓存;取到对象A后就可以成功的给B对象注入A对象了,从而完成B对象的实例化,然后再将B对象从三级缓存移除,放入到一级缓存singletonObjects中,这个时候返回对象B给A以完成A对象属性的注入,此时A对象也完成实例化过程,将其放入一级缓存,同时从二级缓存移除。至此,循环依赖完美解决!!!

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//先到一级缓存singletonObjects拿A对象,这里都是已经实例化完成的对象,在创建中的对象不会得到
	Object singletonObject = this.singletonObjects.get(beanName);
	//如果一级缓存拿不到,因为二级缓存和三级缓存缓存的对象的状态都是处于正在创建中,
	//所以这里会通过方法isSingletonCurrentlyInCreation(beanName)检查A是否正在创建中,
	//然后才会尝试去二级和三级缓存拿,如果没有直接跳过以提高效率;
	//如果beanName对应的对象正在创建中,再尝试从二级缓存earlySingletonObjects中拿,即提前曝光正在创建中的对象
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				//如果二级缓存依然没有拿到,这时候会校验allowEarlyReference是否应该提前曝光对象(是否允许从singletonFactories中通过getObject拿到对象)
				//如果是true则会从singletonFactories获取
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					singletonObject = singletonFactory.getObject();
					//这里是将对象从三级缓存移除,加入到二级缓存内
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

 

PS:这里面还有很多方法还没仔细分析,没有做记录;这里先将整个流程记录下来,后面在对每一个方法分析,期待所以过程搞懂的那一刻,努力吧....

 

 

参考文献:https://www.jianshu.com/p/6c359768b1dc

                 https://www.cnblogs.com/leftthen/p/5440107.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring循环依赖是指两个或多个Bean之间相互依赖,形成一个循环引用的关系。在Spring容器启动的过程中,如果存在循环依赖,那么默认情况下会抛出BeanCurrentlyInCreationException异常。 下面是Spring循环依赖分析: 1. 当我们向Spring容器中注入一个Bean时,Spring会先检查这个Bean是否已经正在创建中(正在创建的Bean是无法注入的),如果正在创建中,则直接返回一个早期引用,否则继续创建Bean。 2. 在Bean的创建过程中,当遇到依赖注入(如@Autowired注解)时,Spring会检查要注入的Bean是否已经在创建中。如果是,则返回一个代理对象作为占位符,等待真正的Bean创建完毕后再进行注入。 3. Spring使用三级缓存来解决循环依赖问题。第一级缓存是单例池,存放已经创建好的单例Bean。第二级缓存是提前暴露的ObjectFactory,存放早期引用。第三级缓存是用于存放正在创建中的Bean的缓存,用于检测循环依赖。 4. 当检测到循环依赖时,Spring会尝试使用构造函数的方式完成循环依赖。它会先创建一个空对象,并将其放入到第三级缓存中。然后调用构造函数去创建这个Bean,此时依赖的Bean会返回一个早期引用。最后,将这个Bean加入到第一级缓存中,并开始注入依赖。 5. 当所有的Bean都创建完成后,Spring会触发后置处理器的回调方法,完成Bean的初始化。 总结:Spring循环依赖通过使用三级缓存和构造函数来解决,在Bean创建过程中动态地判断和处理循环依赖关系,确保所有的Bean都能被正确地创建和注入。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值