Spring Bean 加载解决循环依赖源码分析

概述

Bean 的加载涉及到 获取 Bean 定义,实例化、属性填充、初始化过程。

在初始化阶段 ,Spring 对 Aware、BeanPostProcessor 等扩展点进行了实现,对 Bean 进行增强。

在初始化阶段,有将 Bean 放到三级缓存,然后到二级缓存,最后初始化完成放到一级缓存的过程,具体可以看看上篇文章。

Spring Bean 加载过程生命周期源码分析

注意:

  • Spring 只解决了单例 Bean 循环依赖的情况
  • 依赖注入的方式不能全是构造器注入

样例代码

样例代码只包含 3 个类,启动类 SpringBeanCircleApplication ,CircularServiceA 依赖 CircularServiceB,CircularServiceB 依赖 CircularServiceA 。

@SpringBootApplication
public class SpringBeanCircleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBeanCircleApplication.class, args);
    }
}

@Service
public class CircularServiceA {

    @Autowired
    private CircularServiceB circularServiceB;
}

@Service
public class CircularServiceB {

    @Autowired
    private CircularServiceA circularServiceA;
}

源码分析

循环依赖的 Bean 加载流程:

  1. A 的加载流程包括实例化、属性填充、初始化三个阶段。A 实例化完成之后,会将 Bean 标记为创建中(还未属性填充、初始化)、并且实例的 objectFactory 加入到三级缓存。其中在 A 属性填充阶段,发现 B 还未加载,进而去执行 B 的加载流程

  2. B 的加载流程和 A 一样,B 实例化完成后,会将 B 标记为创建中、加入到三级缓存。此时三级缓存中有 A、B 的 ObjectFactory。

  3. 在 B 属性填充阶段,又发现 A ,进而又去加载 A 。加载 A 发现其正在创建中,并且三级缓存中有 A,那么将 A 放到二级缓存,并返回 A 的引用。

  4. 至此 B 属性填充完成,再执行 B 初始化,初始化完成后将 B 从三级移动到二级再移动到一级缓存中。

  5. 再执行 A 属性填充后的初始化流程,并放到一级缓存。最终,一级缓存里面包含 A 和 B 初始化完成的实例

沿用网上一张图片:
在这里插入图片描述

1. getBean(A)

A 的加载流程

1.1 AbstractBeanFactory

  • 从 getBean 开始,首先从缓存中获取(这个步骤很重要
  • 若缓存中没有,再获取 A 的定义,其次调用 getSingleton 去获取 A 的实例,createBean 方法用于创建 A 的 objectFactory。
  • 若缓存中有,直接返回实例
public abstract class AbstractBeanFactory {
    public Object getBean(String name) throws BeansException {
        return this.doGetBean(name, (Class)null, (Object[])null, false);
    }

    protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    	Object sharedInstance = this.getSingleton(beanName); // 从缓存中获取 A,第一次显然获取不到
		try {
			RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName); // 获取 Bean 定义
			 if (mbd.isSingleton()) {
			 		// 获取 A 的实例
                    sharedInstance = this.getSingleton(beanName, () -> {
                        try {
                            return this.createBean(beanName, mbd, args); // 执行 singletonFactory.getObject 会被调用
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });
                    beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
		}
    }
}

1.2 DefaultSingletonBeanRegistry

  • getSingleton(String beanName, ObjectFactory<?> singletonFactory) 执行到 singletonFactory.getObject 这一行时,会调用函数调用的地方 Lamda 表达式的 AbstractAutowireCapableBeanFactory.createBean 方法

  • getSingleton 方法结束部分,表示 Bean 已经初始化完成,此时移除 Bean 创建中标记,并加入到一级缓存中

public class DefaultSingletonBeanRegistry {
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		synchronized(this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName); // 再次从缓存中获取 A,显然获取不到
			if (singletonObject == null) {
				 this.beforeSingletonCreation(beanName);  // 标记创建中,加入到 singletonsCurrentlyInCreation
				 try {
                    singletonObject = singletonFactory.getObject();  // 执行 lamda 表达式,AbstractAutowireCapableBeanFactory.createBean 返回 实例
                    newSingleton = true;
                } finally {
                	// A 加载结束,移除正在创建标记 singletonsCurrentlyInCreation
					this.afterSingletonCreation(beanName);  
				}
				if (newSingleton) {
					// 添加到一级缓存,删除二级缓存与一级缓存
                    this.addSingleton(beanName, singletonObject);
                }
			}
		}
	}
}    

1.3 AbstractAutowireCapableBeanFactory

执行具体 Lamda 表达式的内容,注意属性填充前,将对象加入的三级缓存的部分,后面会说到三级缓存的作用

public abstract class AbstractAutowireCapableBeanFactory {
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
		beanInstance = this.doCreateBean(beanName, mbdToUse, args);
	}

	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
		if (instanceWrapper == null) {
            instanceWrapper = this.createBeanInstance(beanName, mbd, args); // A 实例化
        }
        // 是否单例 && 运行循环依赖 && 创建中
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
        	// 将对象放到三级缓存
            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }
        try {
            this.populateBean(beanName, mbd, instanceWrapper); // 属性填充(此时发现 A )
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);  // 初始化
        }
        if (earlySingletonExposure) {
        	// 只从一级缓存和二级缓存中取
			Object earlySingletonReference = this.getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
                    exposedObject = earlySingletonReference;
                }
			}
		}
	}
}

// 属性填充
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	if (resolvedAutowireMode == 1 || resolvedAutowireMode == 2) {
	    MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);
	    if (resolvedAutowireMode == 1) {
	        this.autowireByName(beanName, mbd, bw, newPvs);
	    }
	
	    if (resolvedAutowireMode == 2) {
	        this.autowireByType(beanName, mbd, bw, newPvs);
	    }
	    pvs = newPvs;
	}
}

protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    for(int var8 = 0; var8 < var7; ++var8) {
        String propertyName = var6[var8];
        if (this.containsBean(propertyName)) {  // 如果含有 Bean,那么执行 Bean 加载逻辑
            Object bean = this.getBean(propertyName);  // A 发现 B,那么执行 B 的加载流程
        } 
    }

}

可以发现,在 A 的 populateBean 阶段,会去调用 getBean(B) 的逻辑

2. getBean(B)

B 的加载流程,其加载流程和 A 一样(1.1,1.2,1.3 部分)

重点来了,在 B 的 populateBean 阶段,又发现了 A,此时再去执行 getBean(A)

3. getBean(A)

A 再次被加载

AbstractBeanFactory.getBean 方法开头,发现此时三级缓存中有 A 的 ObjectFactory,并且标记为创建中,那么把 A 的 ObjectFactory 从三级缓存(singletonFactories)放到二级缓存(earlySingletonObjects)中,并返回 A 的提前曝光实例(还未初始化完成)

public abstract class AbstractBeanFactory {
    protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        Object sharedInstance = this.getSingleton(beanName);
		if (sharedInstance != null && args == null) {
            beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
        }
}


public class DefaultSingletonBeanRegistry{
    @Nullable
    public Object getSingleton(String beanName) {
        return this.getSingleton(beanName, true);
    }
	
	// 从缓存获取逻辑
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName); // 从一级缓存获取
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {  // 没有获取到并且正在创建中
            singletonObject = this.earlySingletonObjects.get(beanName);  // 从二级缓存获取
            if (singletonObject == null && allowEarlyReference) {  // 二级缓存也没有获取到,并且允许提前返回引用
                synchronized(this.singletonObjects) { // 加锁
                    singletonObject = this.singletonObjects.get(beanName);  // 再次从一级缓存获取
                    if (singletonObject == null) { // 一级没有
                        singletonObject = this.earlySingletonObjects.get(beanName); // 二级中获取
                        if (singletonObject == null) { // 二级也没有
                            ObjectFactory<?> singletonFactory =   (ObjectFactory)this.singletonFactories.get(beanName);  // 从三级获取
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);  // 从三级中获取到了,删除三级缓存,加入到二级缓存中
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
        return singletonObject;
    }
}    

4. B 初始化完成

上一步 B 属性填充完成之后,执行 AbstractAutowireCapableBeanFactory 中后续的初始化流程、并在 DefaultSingletonBeanRegistry.getSingleton 方法最后,移除 Bean 创建中标记,将缓存从三级移到一级。

5. A 初始化完成

与上面步骤一样

为什么需要三级缓存

根据上面流程可知,A、B 的加载,首先都会放到三级缓存中,当再次调用 getBean(A) 方法时,从三级缓存中通过 ObjectFactory.getObject 获取 A 的实例。

若 A 被 AOP 代理,那么执行匿名表达式的exposedObject = bp.getEarlyBeanReference(exposedObject, beanName)操作,返回的是 A 的代理对象
在这里插入图片描述
可以用反证法证明三级缓存的必要性:

  • 若只有两级缓存,创建 A 实例时,不知道是否有循环依赖,先将 A 放到二级缓存;创建 B 实例时,也放入二级缓存。
  • B 属性填充阶段发现了 A,进从二级缓存中找到了 A,若 A 被 AOP 代理,此时从二级缓存中获取的 A 是原始对象并不是代理对象,不符合要求。
  • 若一开始将 A 的代理对象放入二级缓存,这样违背了 Spring AOP 与 Bean 的生命周期的设计,因为在没有循环依赖的常规情况下,AOP 的实现都是 Bean 初始化完成之后才进行。
  • 所以若出现了循环依赖,三级缓存就很有必要,把实例对象的 ObjectFactory 放到三级缓存中,通过 singletonFactory.getObject() 方法判断是否需要返回 A 的代理类,对 A 提前做增强。
public abstract class AbstractAutowireCapableBeanFactory {

	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
        // 是否单例 && 运行循环依赖 && 创建中
        boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
        if (earlySingletonExposure) {
        	// 将对象放到三级缓存
            this.addSingletonFactory(beanName, () -> {
                return this.getEarlyBeanReference(beanName, mbd, bean);
            });
        }
	}

    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        SmartInstantiationAwareBeanPostProcessor bp;
        // 有代理
        if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
            // for 循环参数结尾,返回实例的提前曝光对象
            for(Iterator var5 = this.getBeanPostProcessorCache().smartInstantiationAware.iterator(); var5.hasNext(); exposedObject = bp.getEarlyBeanReference(exposedObject, beanName)) {
                bp = (SmartInstantiationAwareBeanPostProcessor)var5.next();
            }
        }
		// 返回可能被代理的对象
        return exposedObject;
    }
}

循环依赖情况

依赖情况依赖注入方式循环依赖是否被解决
AB相互依赖(循环依赖)均采用 setter 方法注入
AB相互依赖(循环依赖)A中注入B的方式为setter方法
AB相互依赖(循环依赖)B中注入A的方式为 setter 方法,A中注入B的方式为构造器
AB相互依赖(循环依赖)B中注入A的方式为setter方法,A中注入B的方式为构造器是(可以使用 @Lazy 解决
  1. Spring 创建 Bean 是按照自然排序,若主 Bean 是 setter 方式,那么依赖 Bean 是 setter 注入或者构造器注入,都可以解决循环依赖问题

  2. 均使用构造器注入,可以使用 @Lazy 解决,其基本思路是:对于强依赖的对象,一开始并不注入对象本身,而是注入其代理对象

    @Service
    public class CircularServiceA {
        private CircularServiceB circularServiceB;
        public CircularServiceA(@Lazy CircularServiceB circularServiceB){
            this.circularServiceB = circularServiceB;
        }
    }
    
    @Service
    public class CircularServiceB {
        private CircularServiceA circularServiceA;
        public CircularServiceB(CircularServiceA circularServiceA){
            this.circularServiceA = circularServiceA;
        }
    }
    

参考

面试必杀技,讲一讲Spring中的循环依赖

Spring 循环依赖及解决方式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值