Spring源码分析系列——循环依赖解析(附详尽流程图)
本文分析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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)