• Spring源码分析(十五)循环依赖2:源码分析


    源码分析1:三级缓存

    假设单例A、单例B之间循环依赖

    假设先创建A

    org.springframework.context.support.AbstractApplicationContext#getBean(java.lang.String)
    org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
    org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

    在这里插入图片描述

    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory)

    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 (logger.isDebugEnabled()) {...}
                //1.标记A正在创建中
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {...}
                try {
                    //实际会调用createBean方法
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                catch (IllegalStateException ex) {...}
                catch (BeanCreationException ex) {...}
                finally {...}
                if (newSingleton) {...}
            }
            return singletonObject;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {
    
        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {...}
        
        //实例化阶段
        if (instanceWrapper == null) {...}
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {...}
    
        // Allow post-processors to modify the merged bean definition.
        //BeanDefintion后置处理阶段
        synchronized (mbd.postProcessingLock) {...}
    
        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        // 急切地缓存单例,以便能够解析循环引用,即使是由BeanFactoryAware等生命周期接口触发的。
    
        // 是单例、且允许循环依赖(allowCircularReferences默认是true)、
        // 且当前Bean正在创建中(getSingleton的时候已经标记创建中了)
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {...}
            //2. 添加三级缓存
            // 往三级缓存中添加ObjectFactory
            // 此时还不知道会不会出现循环依赖,后面也许会用到,也许用不到。
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }
    
        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            //属性填充阶段(假设A要注入B,注入的过程中最终会再次调getBean拿B)
            populateBean(beanName, mbd, instanceWrapper);
            //初始化阶段
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {...}
    
        if (earlySingletonExposure) {...}
    
        // Register bean as disposable.
        try {...}
        catch (BeanDefinitionValidationException ex) {...}
    
        return exposedObject;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    在这里插入图片描述

    可以让容器关闭循环依赖:


    在这里插入图片描述

    1.标记A正在创建中

    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#beforeSingletonCreation

    protected void beforeSingletonCreation(String beanName) {
        //inCreationCheckExclusions:当前从创建检查中排除的bean的名称。
        //singletonsCurrentlyInCreation:往这个集合中添加元素,如果已经存在返回false,说明已经在创建中了
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2. 添加三级缓存

    是单例、且允许循环依赖(allowCircularReferences默认是true)、且当前Bean正在创建中,则添加三级缓存。
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                //singletonFactories三级缓存
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    A属性填充阶段注入B

    创建A的过程中,到了属性填充阶段,就会开始注入B了,此时会再次调getBean找B

    org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

    protected <T> T doGetBean(
            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
            throws BeansException {
    
        String beanName = transformedBeanName(name);
        Object beanInstance;
    
        // Eagerly check singleton cache for manually registered singletons.
        // 1. 先从单例池中找B,肯定找不到B,且B还没有开始创建
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {...}
        else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            if (isPrototypeCurrentlyInCreation(beanName)) {...}
    
            // Check if bean definition exists in this factory.
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {...}
    
            if (!typeCheckOnly) {...}
    
            StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
                    .tag("beanName", name);
            try {
                if (requiredType != null) {...}
                RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
    
                // Guarantee initialization of beans that the current bean depends on.
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {...}
    
                // Create bean instance.
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            //2. 创建单例B
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {...}
                    });
                    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
                else if (mbd.isPrototype()) {...}
                else {...}
            }
            catch (BeansException ex) {...}
            finally {...}
        }
        return adaptBeanInstance(name, beanInstance, requiredType);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    1. 先从单例池中找B

    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)

    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }
    
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // Quick check for existing instance without full singleton lock
        Object singletonObject = this.singletonObjects.get(beanName);
        // 此时单例池中是找不到B的,并且B还没有在创建中
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {...}
        return singletonObject;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    检查是否正在创建中:
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#isSingletonCurrentlyInCreation

    public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }
    
    • 1
    • 2
    • 3

    此时单例池中是找不到B的,并且B还没有在创建中,所以会开始创建B。
    同理B也会先标记B正在创建中,然后添加三级缓存,到了B属性填充阶段,会去注入A

    B属性填充阶段注入A

    创建B的过程中,到了属性填充阶段开始注入A,此时会再次调getBean找A

    org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

    protected <T> T doGetBean(
            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
            throws BeansException {
    
        String beanName = transformedBeanName(name);
        Object beanInstance;
    
        // Eagerly check singleton cache for manually registered singletons.
        // 急切地检查手动注册的单例缓存。
    
        // 1.从三级缓存中找A
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {...}
        else {...}
    
        return adaptBeanInstance(name, beanInstance, requiredType);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    1. 从三级缓存中找A

    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)

    public Object getSingleton(String beanName) {
        return getSingleton(beanName, true);
    }
    
    //allowEarlyReference:是否允许创建早期引用
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // Quick check for existing instance without full singleton lock
        Object singletonObject = this.singletonObjects.get(beanName);
        // 此时单例池中是找不到A的,但是发现A已经在创建中了
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            //去二级缓存拿,此时也拿不到的
            singletonObject = this.earlySingletonObjects.get(beanName);
            //拿不到判断是否允许创建早期引用,此时allowEarlyReference=true
            if (singletonObject == null && allowEarlyReference) {
                synchronized (this.singletonObjects) {
                    // Consistent creation of early reference within full singleton lock
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            //允许创建早期引用,则拿三级缓存创建
                            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                //执行三级缓存的getObject拿到最终需要注入的对象
                                //此时如果是AOP则返回代理对象,不是AOP返回普通对象
                                singletonObject = singletonFactory.getObject();
                                //将三级缓存生成的对象(最终注入的对象)放到二级缓存
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                //用不到了,就移除了
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
        //此时返回"半成品"对象
        return singletonObject;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    解决循环依赖,其实核心代码就两段逻辑,一个是放入三级缓存,一个从三个缓存中取值

    源码分析2:AOP情况针对循环依赖的处理

    保证不会重复AOP生成代理对象

    如果发生循环依赖,且是AOP情况,会提前生成代理对象
    在这里插入图片描述
    而正常流程是在初始化后生成代理对象的
    所以初始化后这里肯定要做一个控制,如果已经提前进行过AOP就不能再进行AOP了

    看下提前进行AOP执行的代码:

    在这里插入图片描述

    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference

    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
                //提前AOP,代表发生循环依赖,且会调getEarlyBeanReference
                //正常AOP,无论是否发生循环依赖,都会调postProcessAfterInitialization
                exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
        return exposedObject;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    只关心AOP的实现:
    org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference

    //发生循环依赖才会调用这个方法,提前获取bean引用
    public Object getEarlyBeanReference(Object bean, String beanName) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        //记录一下当前Bean发生了循环依赖,并提前获取Bean引用了
        
        //即记录当前Bean进行了AOP,注意此时bean是原始对象
        this.earlyProxyReferences.put(cacheKey, bean);
        //AOP,返回代理对象
        return wrapIfNecessary(bean, beanName, cacheKey);
    }
    
    //同时对比一下初始化后执行的方法,无论是否发生循环依赖都会执行
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                //earlyProxyReferences里取的是null != bean,说明之前没进行过AOP,才会进行AOP
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        //当前正在创建的Bean不用进行AOP,比如切面Bean
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    
        // Create proxy if we have advice.
        // 判断当前Bean是否存在匹配的advice,如果存在则要生成一个代理对象
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
            //advisedBeans记录了某个Bean已经进行过AOP了
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            Object proxy = createProxy(
                    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());
            //要AOP,返回代理对象
            return proxy;
        }
    
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        //不要AOP,返回普通对象
        return bean;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    保证最终单例池里放入正确的对象

    A在初始化后发现已经提前AOP了,就不会再进行AOP了,之后要把A放到单例池里去
    思考一下,此时放到单例池里的是原始对象还是代理对象?

    再看一下初始化后的方法:

    在这里插入图片描述

    AOP的实现:

    在这里插入图片描述

    即初始化后方法得到的对象,有两种情况:

    • 如果提前AOP了(发生循环依赖了),初始化后方法得到的就是原始对象
    • 如果没有提前AOP(没有发生循环依赖),初始化后方法得到的就是代理对象

    如果发生循环依赖,提前AOP生成代理对象,虽然在初始化后阶段不会重复生成代理对象,但返回出去的是原始对象,而最终放入单例池的肯定希望是AOP的代理对象,那从哪里获得?二级缓存。

    看下初始化后之后做了什么:
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {
    
        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {... }
        //实例化阶段
        if (instanceWrapper == null) {...}
        Object bean = instanceWrapper.getWrappedInstance();
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {...}
        
    	//BeanDefinition后置处理
        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {...}
    
        // 循环依赖 - 设置三级缓存
        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {...}
    
        // Initialize the bean instance.
        Object exposedObject = bean;
        try {
            //属性填充阶段
            populateBean(beanName, mbd, instanceWrapper);
            
            //初始化阶段(初始化前、初始化、初始化后)
            //注意,如果没有发生循环依赖,这里得到的就是代理对象
            //如果发生了循环依赖,这里得到的就是原始对象(大部分情况)
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {...}
    
        //关键这里!!
        if (earlySingletonExposure) {//如果支持循环依赖
            //再次getBean,此时会从二级缓存拿到对象!!此时二级缓存存的就是“最终的"对象引用
        	//本质是执行多次SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference得到的对象
            Object earlySingletonReference = getSingleton(beanName, false);
            //能拿到,说明发生了循环依赖!!!
            if (earlySingletonReference != null) {
                //发生循环依赖以后
                //exposedObject:初始化后得到的对象
                //bean:一开始实例化的原始对象
                //比较  初始化后拿到的对象  和 一开始实例化的原始对象
                if (exposedObject == bean) {//大部分情况肯定一样的,先考虑简单场景
                    //一样的话拿二级缓存的,替换exposedObject,最终返回
                    //所以哪怕发生循环依赖,也能正常返回最终的那个代理对象
                    exposedObject = earlySingletonReference;
                }
                //下面这段逻辑是处理:初始化后替换的对象 与 提前获取引用生成的对象 不一样冲突的情况
                //比较复杂,感兴趣就看https://www.yuque.com/qhao/framework/dxfpaw#FjcPV
                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {...}
        }
    
        // Register bean as disposable.
        try {...}
        catch (BeanDefinitionValidationException ex) {...}
        return exposedObject;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    所以哪怕发生循环依赖,也能通过二级缓存,正常返回最终的那个代理对象

  • 相关阅读:
    CSS - 响应式布局(一)媒体查询
    用jQuery向FCKEditor插件取值、赋值
    ASP.NET Core WebApi返回结果统一包装实践
    Ubuntu GDB 的基本使用-传参调用
    概率统计面试题
    使用flex布局实现,7种经典布局案例
    Windows上配置IP端口转发
    如果你是一个 Java 面试官,你会问哪些问题?
    2022年最新《谷粒学院开发教程》:6 - 整合SpringCloud
    数据结构 | 二叉树
  • 原文地址:https://blog.csdn.net/weixin_41947378/article/details/127715197