前言
本文分析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。
原文链接:https://blog.csdn.net/Maybe_9527/article/details/112303239
标签:缓存,流程图,Spring,beanName,Object,bean,源码,单例,创建 From: https://www.cnblogs.com/hefeng2014/p/17769807.html