为了账号安全,请及时绑定邮箱和手机立即绑定

spring源码分析(三)bean的生命周期之初识循环依赖

标签:
Java
final AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);

问题:当我们用@ComponentScan扫包的时候会发生什么呢?
BeanA依赖BeanB 然后 BeanB也依赖BeanA的情况(先说@Autowired和setter的情况)

1.AnnotationConfigApplicationContext点进去我们就能看到代码

从这里开始就是源码的世界

    public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
        this();
        this.register(componentClasses);
        this.refresh();
    }

2.this.refresh();

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var10) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
                }

                this.destroyBeans();
                this.cancelRefresh(var10);
                throw var10;
            } finally {
                this.resetCommonCaches();
                contextRefresh.end();
            }

        }
    }

3.this.initApplicationEventMulticaster(); 这行代码的作用就是我在第一篇文章中写到的把需要依赖注入的类扫描完成的步骤

重要的我们的依赖注入this.finishBeanFactoryInitialization(beanFactory); 是在这里面实现的,怎样去证明:

4.我们在需要注入的类的无参构造方法中写一个sout语句

package com.springbeanDemo.pojo;

import org.springframework.stereotype.Component;

/**
 * 注释
 *
 * @author sunhao
 * @Date 2021-08-09-20:44
 */

@Component
public class User {
    public User() {
        System.out.println("user is value");
    }

    public void say(){
        System.out.println("bbbbb");
    }
}

  1. this.finishBeanFactoryInitialization(beanFactory); 在这句上面下面分别打上断点,下面的断点就能看到在控制台上打印出user is value
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
            beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
        }

        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver((strVal) -> {
                return this.getEnvironment().resolvePlaceholders(strVal);
            });
        }

        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        String[] var3 = weaverAwareNames;
        int var4 = weaverAwareNames.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String weaverAwareName = var3[var5];
            this.getBean(weaverAwareName);
        }

        beanFactory.setTempClassLoader((ClassLoader)null);
        beanFactory.freezeConfiguration();
        beanFactory.preInstantiateSingletons();
    }

6.这一部分我只贴出来我们需要走向下一个方法的代码

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

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				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);
						}
					}
				}
				else {
					getBean(beanName);
				}
			}
		}

7.List beanNames = new ArrayList(this.beanDefinitionNames);
这个list就是我第一篇文章中写的BeanDefinition加入到map中后又把名字加入到list里面
这里开始循环这个list然后去 beanDefinitionMap 中get出BeanDefinition对象
然后去各种条件判断他是否要现在创建bean
(条件有是!bd.isAbstract()&&bd.isSingleton()&&!bd.isLazyInit())满足之后才会去走主要的方法 8.this.getBean(beanName);

    public Object getBean(String name) throws BeansException {
        return this.doGetBean(name, (Class)null, (Object[])null, false);
    }

一般在看源码的时候只有前面带do的才会干实事
9.this.doGetBean
代码很长 我只贴出来这里需要重点看的部分 避免一些小伙伴 看到源码直接被劝退了

这里我先透露一下,咱们有重点的去看源码getSingleton 这个方法是解决循环依赖的关键,这个方法在doGetBean中被调用两次,但是这两次不是相同的方法 , 他是方法的重载

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
	String beanName = this.transformedBeanName(name);
        Object sharedInstance = this.getSingleton(beanName);
        Object beanInstance;
        if (sharedInstance != null && args == null) {
           ***
        } else {
            ***
                if (mbd.isSingleton()) {
                    sharedInstance = this.getSingleton(beanName, () -> {
                        try {
                            return this.createBean(beanName, mbd, args);
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });
				***
}
 

10.上面我先贴出来第一次调用getSingleton 这个部分的源码 我们点进去会看到这样的一段源码

这里给大家分享一个debug源码的小技巧,因为这里会有很多spring容器自己的bean 所以我们在阅读源码的时候会产生很多的干扰
图片描述

这样我们就能控制只要beanName为user的分支

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

11.Object singletonObject = this.singletonObjects.get(beanName);
这里面singletonObjects 就是我们常说的一级缓存,spring的单例池,本质是一个map
假如我们现在是BeanA和BeanB
在这里BeanA初始化的时候走的这个方法 这时候我们肯定会知道 他想得到的BeanA在这个map中不存在 (具体这里为什么明知不存在还要去get下面会讲到)
得到的singletonObject 为空 走第二个

sharedInstance = this.getSingleton(beanName, () -> {
                        try {
                            return this.createBean(beanName, mbd, args);
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });

12.这里我们点进去就能看到第二段getSingleton 的主要作用 我都会自动过滤掉这个知识点中不重要的代码 方便小伙伴查看

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        synchronized(this.singletonObjects) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                if (this.singletonsCurrentlyInDestruction) {
                    throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)");
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
                }

                this.beforeSingletonCreation(beanName);
			***

            return singletonObject;
        }
    }

当然这里的Object singletonObject = this.singletonObjects.get(beanName); 获取的肯定还是null 然后他就会走到
this.beforeSingletonCreation(beanName); 这个里面 这个的作用就是把我们将要创建的这个beanName放进一个set集合
13.this.singletonsCurrentlyInCreation.add(beanName)

    protected void beforeSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }

这里就标记了 我们将要 创建这个BeanA这个beanName放进set集合中singletonsCurrentlyInCreation
this.singletonsCurrentlyInCreation.add(beanName) 放入到二级缓存 earlySingletonObjects 中

14.这时BeanB也在创建的过程中,同样,走完上面的步骤,BeanB这个beanName放进set集合中singletonsCurrentlyInCreation 被标记为将要创建。

15.这时发现BeanB里面依赖了 BeanA,他会去spring容器中去找A 找不到 他就去创建A
这时就回到了原点 但是这次 他在 二级缓存 earlySingletonObjects 中找到了A这时的A还不是一个Bean 他只是一个待创建的Bean B把A依赖进来 然后 走完完成Bean的创建加入到一级缓存中singletonObjects

16.这时A继续创建,发现A中也依赖了B 这就是典型的 循环依赖, 这次他走到创建B的过程
创建B的过程 Object singletonObject = this.singletonObjects.get(beanName); 这次 get的就不是null了 这就是上面提到的为什么明知道是null还要去 get 这次从单例池中 get到了B 然后A把B加入到属性中 然后走完创建过程 加入到一级缓存中singletonObjects

17 至此 一个简单的循环以来就形成了

总结 循环依赖的 最主要的就是 两个getSingleton 方法的重载

一级缓存:singletonObjects 单例池 单例 Bean 创建完成后就放在 singletonObjects 这个 Map 里面
二级缓存:earlySingletonObjects
earlySingletonObjects 这个 Map 存放提前暴露 Bean 的引用,实例化以后,就把对象放入到这个 Map 中。
b.setA(getBean(“a”)) 在加载 b 的过程中,可以在 earlySingletonObjects 拿到 a 的引用,此时 a 仅仅经过了实例化,并没有设置属性。
getEarlyBeanReference(beanName, mbd, bean)有可能会进行 AOP 的增强,创建代理类,因此二级缓存 earlySingletonObjects 存放的有可能是经过 AOP 增强的代理对像。

点击查看更多内容
1人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消