Spring源码分析系列——循环依赖解析(附详尽流程图)

目录

  • 前言
  • 测试代码准备
  • 执行流程分析
    • DefaultListableBeanFactory.PreInstantiateSingletons()解析
    • 第一个实体类student的getBean()
      • doGetBean()方法分析
        • DefaultSingletonBeanRegistry.getSingleton(beanName)方法分析
        • DefaultSingletonBeanRegistry.getSingleton(beanName,ObjectFactory)重载方法分析
          • createBean()方法分析
            • populateBean()方法分析
    • 第二个实体类teacher的getBean()
      • doCreateBean()创建实例并填充属性
        • 第二个实体类创建完毕,放入单例池,继续回到第一个实体类填充属性方法
  • 疑问
    • 为什么需要三级缓存?只用一级、二级不行吗?
  • 总结
    • spring循环依赖解决方案
    • 解决循环依赖核心执行流程
  • 完整流程图

前言

本文分析spring循环依赖,我们知道

  1. 构造函数填充属性是天然无法解决循环依赖的,而且解决循环依赖必须至少需要一个单例bean提前暴露。
  2. 用xml标签配置属性bean,和@autowire注解注入属性bean,注入属性过程是不一样的。
    (1)xml标签配置属性bean是在解析xml过程中直接将属性值填充到beanDefinition里,在populateBean填充属性时,可以从beanDefinition里读取getPropertyValues。
    (2)@autowire注解注入属性bean,需要用到AutowiredAnnotationBeanPostProcessor用postProcessProperties()方法读取标有@autowire注解的属性。
    本篇采用两个单例bean,通过@autowire注解属性互相依赖,作为例子,解析spring是如何实现循环依赖。

测试代码准备

实体类

/**
 * @author yuxuefei
 * @date 2021/1/6 10:21
 */
@Component("student")
public class Student {

    @Autowired
    private Teacher teacher;

    private String name = "张三";

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "teacher=" + teacher.getName() +
                '}';
    }


}


/**
 * @author yuxuefei
 * @date 2021/1/6 10:22
 */
@Component("teacher")
public class Teacher {
    @Autowired
    private Student student;

    private String name = "马老师";

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "student=" + student.getName() +
                '}';
    }


}

xml配置

<context:component-scan base-package="yxf.spring.circular.bean" >context:component-scan>

运行测试类

/**
 * @author yuxuefei
 * @date 2020/12/25 16:52
 */
public class MyXmlConfig {
    public static void main(String[] args) throws Exception {
        ApplicationContext ac = new ClassPathXmlApplicationContext("yxf/spring/instantiate/application.xml");

        Student student = (Student) ac.getBean("student");
        System.out.println(student);
    }
}

我们准备了Student和Teacher两个实体类,并且互相都用@autowire注入彼此,属性依赖,xml中配置开启注解。下面我们开始分析啦!

执行流程分析

执行流程很长,也比较绕,只看文字很容易绕晕,所以我做了一副流程图,附在文章最后,可以对照流程图来看。
因为都是非懒加载单例bean,所以会在容器初始化阶段提前初始化所有非懒加载bean,我们的分析就从DefaultListableBeanFactory.PreInstantiateSingletons()方法开始。

DefaultListableBeanFactory.PreInstantiateSingletons()解析

代码精简后如下

public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// 遍历所有非懒加载bean,并实例化
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			//非抽象、单例、非懒加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				//实现FactoryBean接口的实例化处理方式
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				//正常bean的实例化方式
				else {
					getBean(beanName);
				}
			}
		}

		
	}

这个方法就是提前把所有非懒加载的单例bean提前实例化,分成两种方式,一种是实现FactoryBean接口的,我们已经在《Spring源码分析系列——bean创建过程分析(四)——实现FactoryBean接口创建bean》这篇文章中解析过了。另一种就是正常的getBean方式。主要流程我们也在之前的spring解析系列文章解析过了,现在我们再解析一些跟单例bean创建的一些细节。
进入getBean(beanName)、doGetBean()方法,我们重点解析doGetBean()方法。此时第一次getBean(beanName)的beanName是"student"。

第一个实体类student的getBean()

直接进入doGetBean()方法,我们重点解析这个方法。

doGetBean()方法分析

精简了很多无关代码,如下

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

		String beanName = transformedBeanName(name);
		Object bean;

		// 首先进一次getSingleton()方法,从单例缓存中取,第一次肯定为null
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {			
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
		
			// 创建单例bean
			if (mbd.isSingleton()) {
				//传入一个ObjectFactory的lambda表达式,这个lambda表达式调用createBean方法真正创建bean实例
				sharedInstance = getSingleton(beanName, () -> {					
					return createBean(beanName, mbd, args);					
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}						
		}		
		return (T) bean;
	}

代码精简之后,就是调用了两次getSingleton()方法,第一次从单例缓存中取,如果没有,就第二次调用getSingleton(),传入一个ObjectFactory的lambda表达式,调用createBean真正创建bean。我们重点看一下getSingleton(beanName)方法。

DefaultSingletonBeanRegistry.getSingleton(beanName)方法分析

看一下完整代码

public Object getSingleton(String beanName) {
		return getSingleton(beanName, allowEarlyReference:true);
	}

调的是重载方法,且allowEarlyReference为true,即允许提前引用,之后还会遇到别的地方调用这个方法,只不过传的是false

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//从一级缓存里取
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果一级缓存里没有,并且该实例正在创建
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				//从二级缓存里取
				singletonObject = this.earlySingletonObjects.get(beanName);
				//如果二级缓存里没有,并且允许使用使用三级缓存
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//如果有三级缓存
					if (singletonFactory != null) {
						//执行三级缓存的lambda表达式,创建实例
						singletonObject = singletonFactory.getObject();
						//将创建好的实例放入二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						//移除三级缓存
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}
	//一级缓存
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
	//二级缓存
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
	//三级缓存
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

这里就是分别从三级缓存里依次取单例。

DefaultSingletonBeanRegistry.getSingleton(beanName,ObjectFactory)重载方法分析

第一次调用getSingleton(beanName)方法肯定是没有缓存的,所以会继续调用第二个getSingleton(beanName,ObjectFactory)真正创建单例。跟第一个getSingleton不一样的是,第二个getSingleton这个重载方法传入了ObjectFactory这个lambda表达式,这个lambda表达式调用createBean()真正创建单例bean。下面我们来分析getSingleton(beanName,ObjectFactory)这个重载方法。
代码精简之后,如下

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {		
		synchronized (this.singletonObjects) {
			//依然先从一级缓存里取
			Object singletonObject = this.singletonObjects.get(beanName);
			//如果一级缓存没有
			if (singletonObject == null) {	
				//标记这个单例bean正在创建			
				beforeSingletonCreation(beanName);
				//是否新创建的单例bean标记
				boolean newSingleton = false;				
				try {
					//执行lambda表达式,创建bean
					singletonObject = singletonFactory.getObject();
					//新创建单例bean标记为true
					newSingleton = true;
				}				
				catch (BeanCreationException ex) {
					
				}
				finally {
					//移除正在创建的单例bean标记					
					afterSingletonCreation(beanName);
				}
				//新创建的单例bean标记为true
				if (newSingleton) {
					//将新创建的单例bean放入一级缓存,并且将二级、三级缓存移除
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

看一下里面调用的几个简单的方法

//标记这个单例bean正在创建
protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}
	
//移除正在创建的单例bean标记
protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

//将新创建的单例bean放入一级缓存,并且将二级、三级缓存移除
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);
		}
	}
//singletonsCurrentlyInCreation 是一个set,放的是正在创建的单例bean集合,创建完成后就移除
private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

创建student单例bean前后的主流程就比较清晰了,现在来看执行createBean创建student是怎么和创建teacher产生属性依赖,并解决的。

createBean()方法分析

代码精简后,如下

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// bean的包装类
		BeanWrapper instanceWrapper = null;		
		if (instanceWrapper == null) {
			//创建bean实例
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		//真正创建的bean实例
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();		

		//如果是单例、允许循环依赖并且是正在创建中的单例,添加三级缓存singletonFactory
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {			
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		
		Object exposedObject = bean;
		//填充属性
		populateBean(beanName, mbd, instanceWrapper);
		//初始化
		exposedObject = initializeBean(beanName, exposedObject, mbd);
		
		
		//如果是单例、允许循环依赖并且是正在创建中的单例,初始化完还要检验
		if (earlySingletonExposure) {
			//再次调用getSingleton,注意这次传的allowEarlyReference为false,即不从三级缓存里创建bean。
			Object earlySingletonReference = getSingleton(beanName, false);
			//如果有提早暴漏的bean,其实是二级缓存中拿的,而二级缓存中存的其实就是由三级缓存创建的
			if (earlySingletonReference != null) {
				//如果初始化之后的bean和原始bean一样,就采用提早暴漏的bean
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}				
			}
		}

		return exposedObject;
	}

createBean()方法调用createBeanInstance()方法创建bean后,如果是单例、允许循环依赖并且是正在创建中的单例,就添加三级缓存singletonFactory,addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))。lambda表达式中调用getEarlyBeanReference()方法,参数中传入了刚创建好的bean。来看一下这个方法

getEarlyBeanReference(beanName, mbd, bean))

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;
	}

如果忽略掉中间调用的beanPostProcessor,那就是将创建的原生bean再暴漏出去。

接下来就该分析填充属性了,是在populateBean()方法中填充属性,这里就该填充teacher属性了,前面提到过,由xml和@annotation两种方式设置bean定义再populateBean()填充属性时,执行过程时不一样的。我们这里是用的@annotation方式注入属性。

populateBean()方法分析

代码精简后,如下

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		
		//从bean定义中取xml中定义的property属性。这里因为是注解注入属性,用不到
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
		
		//是否有InstantiationAwareBeanPostProcessors标记,这里因为用了注解,肯定有
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();		

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			//遍历所有的BeanPostProcessor
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				//如果是InstantiationAwareBeanPostProcessor
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					//执行postProcessProperties()方法
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
		
		//xml方式注入属性,这里用不到
		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

循环BeanPostProcessor里,真正起作用的是AutowiredAnnotationBeanPostProecessor。至于这些BeanPostProcessor是什么时候加载进来的,因为我们再xml中配置了

<context:component-scan base-package="edu.dongnao.courseware.spring.circular.bean" >context:component-scan>

配置了component-scan标签,就会在ContextNamespaceHandler调用init()、parse()方法时提前实例化这些注解相关的BeanPostProcessor,其中就有AutowiredAnnotationBeanPostProcessor,详情请看这篇《Spring源码分析系列——xml配置非默认元素<context:annotation-config/> 和<context:component-scan/>是如何让注解生效的?》。

再来分析AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,至于postProcessPropertyValues()方法,其实已经废弃
源码如下

@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		//找到标有@autowired注解元信息
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			//注入操作
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

	@Deprecated
	@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {

		return postProcessProperties(pvs, bean, beanName);
	}

继续看InjectionMetadata的inject()方法

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			for (InjectedElement element : elementsToIterate) {
				if (logger.isTraceEnabled()) {
					logger.trace("Processing injected element of bean '" + beanName + "': " + element);
				}
				element.inject(target, beanName, pvs);
			}
		}
	}

element就是标有@autowired的属性

继续看InjectedElement的inject()方法(实际上是AutowiredFieldElement)
代码精简之后,如下

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			//需要注入的属性,标有@autowired属性
			Field field = (Field) this.member;
			Object value;
			//缓存中取,第一次肯定没有
			if (this.cached) {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			else {
				DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
				desc.setContainingClass(bean.getClass());
				Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
				Assert.state(beanFactory != null, "No BeanFactory available");
				TypeConverter typeConverter = beanFactory.getTypeConverter();
				
				//调用beanFactory的resolveDependency()方法,获得属性依赖的bean
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
								
			if (value != null) {
				ReflectionUtils.makeAccessible(field);
				//反射注入属性
				field.set(bean, value);
			}
		}

再看beanFactory的resolveDependency()方式是如何获取属性bean的
代码精简之后,如下

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		
	}

就是委托给doResolveDependency()方法
代码精简后,如下

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

		
		try {
			

			Class<?> type = descriptor.getDependencyType();	
			
			//找到候选的@autowired注解属性,Object有可能是Class也有可能bean
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			

			String autowiredBeanName;
			Object instanceCandidate;
			
			//多个候选bean时处理方案
			if (matchingBeans.size() > 1) {
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
					}
					else {						
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			//只有一个候选时
			else {
				// We have exactly one match.
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}

			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			//如果是Class则解析成bean
			if (instanceCandidate instanceof Class) {
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			
			
			return result;
		}
		
	}

再来看DependencyDescriptor.resolveCandidate()方法

public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
			throws BeansException {

		return beanFactory.getBean(beanName);
	}

很明显,调用的是getBean(beanName)方法获取需要注入的属性bean:“teacher”。
下面开始第二个bean,"teacher"的getBean()

第二个实体类teacher的getBean()

已经来到了第二个实体类teacher的getBean(),继续doGetBean()。在第一个实体类student的getBean()中已经对doGetBean()解析过了,是会执行两次getSingleton()方法(两次是不一样的重载方法),我们再来简单看一下

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

doCreateBean()创建实例并填充属性

不再分析了,接着跟创建student时流程一样,都是执行createBeanInstance()创建bean实例,然后进入populateBean()填充属性阶段。这时候student和teacher都处于populateBean()填充属性阶段,一级缓存和二级缓存中都没有student和teacher的缓存,而在三级缓存中已经包含了student和teacher的缓存创建工厂,因为两者都执行完了createBeanInstance()创建实例方法,在createBeanInstance()和populateBean()方法之间会把三级缓存用的缓存创建工厂加入到三级缓存,调用的是addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))方法。
所以在teacher填充student属性时,调用getBean(“student”)方法,再调用doGetBean(),再第一次调用getSingleton()方法,因为allowEarlyReference=true,所以会调用三级缓存,执行ObjectFactory的lambda表达式,获取回调创建的bean。执行完后再把三级缓存移除,放入二级缓存。
由此,可以看出来了,在创建第一个实体类student的时候提前暴露到三级缓存,然后在第二个实体类创建后进入填充属性过程getBean()时,直接从三级缓存中拿到第一个实体类的bean,从而解决死循环问题。

第二个实体类创建完毕,放入单例池,继续回到第一个实体类填充属性方法

第二个实体类teacher填充完属性后,自身继续执行剩下的创建过程,放入一级缓存中,并移除二级、三级缓存。因为第二个实体类teacher的创建是由第一个实体类student在populateBean()填充属性阶段getBean(“teacher”)触发的,所以getBean(“teacher”)执行完后,继续回到student的populateBean()阶段。这个时候student属性赋值为刚创建的teacher。
之后同样将创建完的student放入一级缓存,且移除二级缓存和三级缓存,循环引用完美解决。

疑问

为什么需要三级缓存?只用一级、二级不行吗?

只用一级显然时不行的,因为提前暴漏的bean还没有进行属性赋值和初始化,并不完整,不能给外界用,所以需要一个二级缓存,专门存储只进行了实例化,尚未进行属性赋值和初始化的不完整bean。我们看一下添加三级缓存的代码addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))

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;
	}

就是对刚创建的bean做了一些预留扩展处理,如果没有这些处理,就是直接返回回调的bean。
所以从解决循环依赖的角度看我认为不是必须的,但是spring的强大就是在bean的生命周期各个阶段做了很多扩展,有备无患。这里的SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference(exposedObject, beanName)实际上是做的aop代理增强。具体会在aop相关文章详解。

总结

spring循环依赖解决方案

使用三级缓存解决单例bean的循环依赖,在第一个实体类createBeanInstance()方法创建完bean实例,和populateBean()填充属性之间,添加三级缓存实例创建工厂,实现提前暴漏,这样在第二个实体类填充第一个实体类属性时,通过getSingleton()方法获取三级缓存中提前暴漏的第一个实体类创建的bean,从而解决循环依赖。

解决循环依赖核心执行流程

我们使用beanA指代第一个实体类,beanB指代第二个实体类。
1.beanA开始创建=== 》
2. getBean() === 》
3. doGetBean() === 》
4. 第一次getSingleton(),无缓存单例 === 》
5. 第二次getSingleton(),执行ObjectFactory 的createBean()创建bean实例 === 》
6. doCreateBean() === 》
7. createBeanInstance()创建bean实例 === 》
8. 三级缓存中添加beanA的缓存创建工厂,提前暴漏beanA === 》
9. populateBean()填充属性,执行过程中,调用getBean(),开始创建beanB === 》
10. getBean() === 》
11. doGetBean() === 》
12. 第一次getSingleton(),无缓存单例 === 》
13. 第二次getSingleton(),执行ObjectFactory 的createBean()创建bean实例 === 》
14. doCreateBean() === 》
15. createBeanInstance()创建bean实例 === 》
16. 三级缓存中添加beanB的缓存创建工厂,提前暴漏beanB,(对于只有beanA和beanB循环依赖,beanB的缓存创建工厂没有用到,如果是beanA、beanB、beanC三者循环依赖,就会用到了) === 》
17. populateBean()填充属性,执行过程中,调用getBean(),尝试获取beanA === 》
18. getBean() === 》
19. doGetBean() === 》
20. 第一次getSingleton(),从三级缓存中调用缓存创建工厂,回调一开始创建的beanA(beanA此时还在执行populateBean填充beanB中)=== 》
21. 拿到beanA,直接返回,完成populateBean() === 》
22. initializeBean()初始化 === 》
23. 完成beanB的创建、属性填充、初始化,并放入一级缓存,移除二级、三级缓存 === 》
24. beanA的populateBean填充属性beanB完成 === 》
25. initializeBean() 初始化 === 》
26. 完成beanA的创建、属性填充、初始化,并放入一级缓存,移除二级
、三级缓存 。至此,beanA和beanB都创建完毕,并放入一级缓存中。

以上完整流程,从头到尾都是在beanA的创建过程中,从9-23都是在执行populateBean()方法对beanA属性填充beanB,所以会开始beanB的创建。
在第8步中,关键的在三级缓存中添加beanA的缓存创建工厂,提前暴漏beanA,所以在20步beanB填充属性beanA时,调用getSingleton才能拿到三级缓存中的beanA。

完整流程图

Spring源码分析系列——循环依赖解析(附详尽流程图)_第1张图片

你可能感兴趣的:(源码,spring,spring,java)