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