浅析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进行判断,如果类型不匹配,会尝试进行类型转换。
//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方法调用
//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添加到缓存中。添加缓存的逻辑下文会分析。
//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-method
和replace-method
,这两个配置会统一在BeanDefinition的methodOverrides属性中。 -
此外还可以在真正创建实例的时候的,通过BeanPostProcessor接口返回一个代理类,而不去真正创建实例。此特性容易被忽略,但却有至关重要的作用,AOP的功能就是基于此处判断。
-
最后会去调用doCreateBean真正创建实例(实例化、设置属性、初始化),此处的逻辑可以参考本人另外一篇文章:【浅析Spring Bean的生命周期】
//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方法
//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;
}
//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;
}
//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。简单梳理一下调用链路
@Component
public class A{
@Autowired
private B b;
}
依赖注入会在Bean生命周期中的属性设置中处理,会通过InstantiationAwareBeanPostProcessor(BeanPostProcessor子接口)处理依赖注入。
//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方法处理,调用链路如下:
//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,然后获取到的数据通过反射的方式设置到数据中。
//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方法
//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方法
//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之前有创建,那么直接从缓存中获取,如果还没有创建,那么会触发创建。
//DependencyDescriptor#resolveCandidate
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}
3. Bean循环依赖
默认情况下,Spring支持循环依赖,但是也可以通过接口把禁用。例如:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.setAllowCircularReferences(false);
根据前面的描述,如果Bean都还没有创建的情况下。在创建A的时候,会去创建B,在创建B的时候,又会去创建A,这样就会造成了循环的依赖。Spring的解决方案,额外缓存了正在创建A的实例。
@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创建完才会存储。
//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获取。
//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中。
- bean是单例
- Spring允许循环依赖,可以设置修改。
- bean正在创建
//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移除。
//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。
//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
//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. 参考资料
- 《Spring源码深度解析》
- Spring源码5.1.x分支