三、浅析Spring循环依赖(源码分析)

浅析Spring 循环依赖

本文将简要分析Spring 循环依赖的解决方案,从Bean的创建流程入口,简要了解一个Bean创建需要有哪些步骤,然后再从Bean的依赖注入入手,了解依赖注入所需要的流程。最后再结合Bean创建和依赖注入,分析循环依赖如何处理。

默认情况下,本文描述的Bean都是在单例的情况下。

1. Bean创建流程

Bean的元信息会通过xml文件或者注解扫描等方式转换成BeanDefinition。对于非延迟的单例Bean,在Spring Context启动的时候,就会做一次预先创建。如果是延迟Bean,在依赖注入时(如@Autowire)或者依赖查找时,会创建Bean。

不论是哪种方式,最后都会调用BeanFactory的getBean()方法。以下分析也是从该入口开始,简单的说明一下单例Bean创建的流程,为后续循环依赖做基础了解。

  • getBean方法实际会调用内部方法doGetBean,从该入口开始。Spring对于单例的Bean会进行缓存,也就是单例的Bean在Spring容器中只会被创建一次。因此在获取Bean是会调用getSingleton方式尝试从缓存中获取Bean,该方法后文再详细展开。

  • 从缓存中获取的Bean可能不一定是我们所需要的,比如此处获取的Bean为FactoryBean,但是实际需要的是FactoryBean的getObject方法返回的对象,此处会做这个逻辑。

  • 此外还会根据所需的类型,对获取的Bean进行判断,如果类型不匹配,会尝试进行类型转换。

java 复制代码
//AbstractBeanFactory#doGetBean
protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, Boolean typeCheckOnly)
      throws BeansException {
	Object bean;
	//1.从缓存中获取bean
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		//2.对从缓存中获取的Bean做一下处理
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}
    //... 创建Bean的逻辑
	if (requiredType != null && !requiredType.isInstance(bean)) {
		try {
            //3. 如果类型不匹配,会尝试类型转换
			T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
			if (convertedBean == null) {
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
			return convertedBean;
		}catch (TypeMismatchException ex) {
			
		}
	}
	return (T) bean;
}

以上是对于从容器缓存获取到Bean的情况,如果获取不到Bean,那么就需要进行创建。会调用getSingleton方法进行处理,其中第二个参数ObjectFactory被封装成createBean方法调用

java 复制代码
//AbstractBeanFactory#doGetBean
protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, Boolean typeCheckOnly)
      throws BeansException {
      
	if (mbd.isSingleton()) {
		sharedInstance = getSingleton(beanName, () -> {
			try {
				return createBean(beanName, mbd, args);
			}catch (BeansException ex) {
			
			}
		});
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}
}

getSingleton方法会在创建Bean之前记录一下Bean正在创建的状态,然后调用ObjectFactory的getObject方法,其实也就是会调用createBean方法。再创建完Bean成功后,会把Bean添加到缓存中。添加缓存的逻辑下文会分析。

java 复制代码
//AbstractBeanFactory#getSingleton
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) {
         //会记录Bean正在创建
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
       
         try {
            //调用ObjectFactory方法 
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }catch(IllegalStateException ex){
             
         }finally{
             //清理Bean正在创建状态
             afterSingletonCreation(beanName);
         } 
         if (newSingleton) {
            //添加到缓存中
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}
  • 在createBean方法内,会对methodOverrides属性进行标记和验证。这里实际对应的是xml配置中的lookup-methodreplace-method,这两个配置会统一在BeanDefinition的methodOverrides属性中。

  • 此外还可以在真正创建实例的时候的,通过BeanPostProcessor接口返回一个代理类,而不去真正创建实例。此特性容易被忽略,但却有至关重要的作用,AOP的功能就是基于此处判断。

  • 最后会去调用doCreateBean真正创建实例(实例化、设置属性、初始化),此处的逻辑可以参考本人另外一篇文章:【浅析Spring Bean的生命周期】

java 复制代码
//AbstractAutowireCapableBeanFactory#createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {

   RootBeanDefinition mbdToUse = mbd;
   // 1.校验以及准备覆盖的方法
   try {
      mbdToUse.prepareMethodOverrides();
   }
   try {
      // 2.BeanPostProcessors一个返回代理对象,来替代真正的实例
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   try {
       //3.处理Bean的创建
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      return beanInstance;
   }
}

resolveBeforeInstantiation相关逻辑如下:如果没有处理过的话,会先调用InstantiationAwareBeanPostProcessor(BeanPostProcessor的子接口)的postProcessBeforeInstantiation方法,如果返回的实例不为空,会再调用BeanPostProcessor的postProcessAfterInitialization方法

java 复制代码
//AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   Object bean = null;
   if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // Make sure bean class is actually resolved at this point.
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
         Class<?> targetType = determineTargetType(beanName, mbd);
         if (targetType != null) {
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            if (bean != null) {
               bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
         }
      }
      mbd.beforeInstantiationResolved = (bean != null);
   }
   return bean;
}
java 复制代码
//AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
         if (result != null) {
            return result;
         }
      }
   }
   return null;
}
java 复制代码
//AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

2. Bean依赖注入

以注解方式为例,比如A中,依赖了B。简单梳理一下调用链路

java 复制代码
@Component
public class A{
   @Autowired
   private B b;
}

依赖注入会在Bean生命周期中的属性设置中处理,会通过InstantiationAwareBeanPostProcessor(BeanPostProcessor子接口)处理依赖注入。

java 复制代码
//AbstractAutowireCapableBeanFactory#populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    //...
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
			pvs = pvsToUse;
		}
	}
}

实际会在AutowiredAnnotationBeanPostProcessor的postProcessProperties方法处理,调用链路如下:

java 复制代码
//AutowiredAnnotationBeanPostProcessor#postProcessProperties
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
   try {
      metadata.inject(bean, beanName, pvs);
   }
   return pvs;
}

InjectionMetadata实际为AutowiredFieldElement,会在内部调用beanFactory.resolveDependency,然后获取到的数据通过反射的方式设置到数据中。

java 复制代码
//AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement#postProcessProperties
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs){
   value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
    
   if (value != null) {
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}

resolveDependency方法内部会有一些类型判断,最终会调调用doResolveDependency方法

java 复制代码
//DefaultListableBeanFactory#resolveDependency
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
      
      result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}

doResolveDependency方法会做各种依赖的判断,但对于本例来说,只需要关注最终会调用DependencyDescriptor的resolveCandidate方法

java 复制代码
//DefaultListableBeanFactory#doResolveDependency
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
			
	instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}

在resolveCandidate方法中,会调用BeanFactory的getBean中,好了,到了这里一切又明了。如果所依赖的Bean之前有创建,那么直接从缓存中获取,如果还没有创建,那么会触发创建。

java 复制代码
//DependencyDescriptor#resolveCandidate
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
      throws BeansException {

   return beanFactory.getBean(beanName);
}

3. Bean循环依赖

默认情况下,Spring支持循环依赖,但是也可以通过接口把禁用。例如:

java 复制代码
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setAllowCircularReferences(false);

根据前面的描述,如果Bean都还没有创建的情况下。在创建A的时候,会去创建B,在创建B的时候,又会去创建A,这样就会造成了循环的依赖。Spring的解决方案,额外缓存了正在创建A的实例。

java 复制代码
@Component
public class A{
   @Autowired
   private B b;
}

@Component
public class B{
   @Autowired
   private A a;
}

先分析一下缓存Bean所用到的数据结构

  • singletonObjects:存储beanName和bean实例的关系
  • singletonFactories:存储beanName和Bean工厂的关系
  • earlySingletonObjects:存储beanName和**早期Bean实例(还在创建中)**的关系,而singletonObjects,是需要Bean创建完才会存储。
java 复制代码
//DefaultSingletonBeanRegistry

//存储beanName和bean实例的关系
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//存储beanName和Bean工厂的关系
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//存储beanName和早期Bean实例(还在创建中)的关系,而singletonObjects,是需要创建完才会存储。
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

3.1 缓存中获取Bean

在前面有说提到,getBean方法会首先从缓存中查找Bean,现在分析一下查找的逻辑,如源码所示,会先尝试从singletonObjects获取,再尝试从earlySingletonObjects获取,最后再尝试从singletonFactories获取。

java 复制代码
//DefaultSingletonBeanRegistry#getSingleton
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 缓存是否存在实例
		Object singletonObject = this.singletonObjects.get(beanName);
    	//缓存实例为空,并且Bean正在创建
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            //从早期Bean中查找
			singletonObject = this.earlySingletonObjects.get(beanName);
            //还是为空,但是允许早期依赖(调用getBean入口allowEarlyReference为true)
			if (singletonObject == null && allowEarlyReference) {
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
                            //会尝试从Bean工厂方法中查找
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
                                //通过bean工厂方法获取实例
								singletonObject = singletonFactory.getObject();
                                //放入早期Bean中
								this.earlySingletonObjects.put(beanName, singletonObject);
                                //bean工厂方法移除
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

3.2 添加bean工厂方法

上述逻辑可以看到可能会从singletonFactories获取Bean,那么singletonFactories数据怎么来的?在doCreateBean方法的时候,会有一段判断,同时满足三个条件会将正在创建bean的对象(此时Bean已经实例化,但是还没有设置属性和初始化)加入singletonFactories中。

  1. bean是单例
  2. Spring允许循环依赖,可以设置修改。
  3. bean正在创建
java 复制代码
//AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
	Boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
	      isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}
}

addSingletonFactory逻辑:当前bean不存在singletonObjects中,因为此时bean还没有初始化,所以singletonObjects中不会包含这个对象。把ObjectFactory加入到singletonFactories中,把早期的bean移除。

java 复制代码
//DefaultSingletonBeanRegistry#addSingletonFactory
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   synchronized (this.singletonObjects) {
      if (!this.singletonObjects.containsKey(beanName)) {
         this.singletonFactories.put(beanName, singletonFactory);
         this.earlySingletonObjects.remove(beanName);
         this.registeredSingletons.add(beanName);
      }
   }
}

添加到singletonFactories的ObjectFactory方法如下:提供扩展,可以通过SmartInstantiationAwareBeanPostProcessor获取bean实例;不然就返回当前正常的创建的bean。

java 复制代码
//AbstractAutowireCapableBeanFactory#getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}

3.3 bean创建后

在bean创建好后(初始化后),会添加到缓存中。把bean实例添加singletonObjects,同时移除singletonFactories和earlySingletonObjects

java 复制代码
//DefaultSingletonBeanRegistry#addSingleton
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);
   }
}

3.4 执行顺序以及缓存数据

对象 关键代码位置 singletonObjects singletonFactories earlySingletonObjects
A DefaultSingletonBeanRegistry#getSingleton - - -
AbstractAutowireCapableBeanFactory#addSingletonFactory - a -
AbstractAutowireCapableBeanFactory#populateBean - a -
B DefaultSingletonBeanRegistry#getSingleton(A获取B) - a -
AbstractAutowireCapableBeanFactory#addSingletonFactory - a,b -
AbstractAutowireCapableBeanFactory#populateBean - a,b -
DefaultSingletonBeanRegistry#getSingleton(B获取A) - b a
DefaultSingletonBeanRegistry#addSingleton(B创建完成) b - a
A DefaultSingletonBeanRegistry#addSingleton(A创建完成) a,b - -

4. 参考资料

  1. 《Spring源码深度解析》
  2. Spring源码5.1.x分支
相关推荐
北极无雪15 分钟前
Spring源码学习(拓展篇):SpringMVC中的异常处理
java·开发语言·数据库·学习·spring·servlet
VXbishe22 分钟前
(附源码)基于springboot的“我来找房”微信小程序的设计与实现-计算机毕设 23157
java·python·微信小程序·node.js·c#·php·课程设计
YONG823_API1 小时前
电商平台数据批量获取自动抓取的实现方法分享(API)
java·大数据·开发语言·数据库·爬虫·网络爬虫
扬子鳄0081 小时前
java注解的处理器
java
Amagi.1 小时前
Spring中Bean的作用域
java·后端·spring
2402_857589361 小时前
Spring Boot新闻推荐系统设计与实现
java·spring boot·后端
繁依Fanyi1 小时前
旅游心动盲盒:开启个性化旅行新体验
java·服务器·python·算法·eclipse·tomcat·旅游
J老熊1 小时前
Spring Cloud Netflix Eureka 注册中心讲解和案例示范
java·后端·spring·spring cloud·面试·eureka·系统架构
蜜桃小阿雯1 小时前
JAVA开源项目 旅游管理系统 计算机毕业设计
java·开发语言·jvm·spring cloud·开源·intellij-idea·旅游
CoderJia程序员甲1 小时前
重学SpringBoot3-集成Redis(四)之Redisson
java·spring boot·redis·缓存