首页 > 编程语言 >Spring源码分析系列——循环依赖解析(附详尽流程图)

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

时间:2023-10-17 15:38:11浏览次数:44  
标签:缓存 流程图 Spring beanName Object bean 源码 单例 创建

前言

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

构造函数填充属性是天然无法解决循环依赖的,而且解决循环依赖必须至少需要一个单例bean提前暴露。
用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。

完整流程图

image

原文链接:https://blog.csdn.net/Maybe_9527/article/details/112303239

标签:缓存,流程图,Spring,beanName,Object,bean,源码,单例,创建
From: https://www.cnblogs.com/hefeng2014/p/17769807.html

相关文章

  • springboot启动流程源码解析(带流程图)
    大致流程如下:初始化SpringApplication,从META-INF下的spring.factories读取ApplicationListener/ApplicationContextInitializer运行SpringApplication的run方法读取项目中环境变量、jvm配置信息、配置文件信息等创建Spring容器对象(ApplicationContext)利用ApplicationCon......
  • 手机直播源码,关于pyqt5弹出提示框
    手机直播源码,关于pyqt5弹出提示框1.软件关闭弹框这类的弹框一般是在整个软件关闭的时候提醒用户是否需要退出整个软件 (构建成函数的方法)    defcloseEvent(self,event):    #关闭窗口触发以下事件      a=QMessageBox.question(self,'退出'......
  • Spring 操作 达梦数据库
    Spring操作达梦数据库 一、前提条件本篇博客以访问本地达梦数据库(DM8)为基础进行演示。(前提:本地已经安装了DM8数据库!)关于Windows安装达梦数据库,请参考博客:Windows安装达梦数据库关于Docker安装达梦数据库,请参考博客:Docker安装达梦数据库关于JDBC方式操作达梦......
  • springboot heapdump信息获取
    springboot信息泄露可能泄漏的路由/api-docs/v2/api-docs/swagger-ui.html/api.html/sw/swagger-ui.html/api/swagger-ui.html/template/swagger-ui.html/spring-security-rest/api/swagger-ui.html/spring-security-oauth-resource/swagger-ui.html/mappings/actua......
  • 简单易用的Spring Boot邮件发送
    ......
  • Spring Boot如何实现邮件发送图片邮件?一文带你学会它!
    ......
  • Spring Boot中的过滤器、拦截器、监听器技巧汇总:让你快速成为大神
    ......
  • Spring Boot 实现审核功能,实战来了!
    一、审核功能实现的方式1、普通方案:经办时入A表,审核后从A表读取数据,然后操作目标B表;优势:思路简单劣势:对后端功能实行高度的嵌入;审核功能数据操作不统一2、弹框式方案:前台实现,操作时判断是否需要权限控制,如果需要,则弹出框,由审核人员进行审核,审核通过后,进行后续操作。优势:对......
  • spring 状态机demo
    spring状态机demo<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-core</artifactId><version>2.0.1.RELEASE</version>......
  • ahooks 源码实现
    ahooks库源码实现state模块useSetState功能点:1.实现类似class组件中setState功能,只更新传入的值,其他值不用更新;2.且可以穿入第二个回调函数参数同步获取更新后的最新state用于操作。import{useState}from'react';exportconstuseSetState=(init={})=>{c......