Spring Boot源码:循环依赖

Posted SunSAS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot源码:循环依赖相关的知识,希望对你有一定的参考价值。

循环依赖

以及

spring是如何解决循环依赖的

循环依赖

通俗来说

就是beanA中依赖了beanB,beanB中也依赖了beanA。

spring是支持循环依赖的,但是默认只支持单例的循环依赖,如果bean中依赖了原型bean,则需要加上lookup方法。

继续之前的项目,改造了People,User类:

@Component
public class People {
    @Autowired
    private User user;
    public People(){
        System.out.println("create People");
    }
}
@Component
public class User {
    @Autowired
    private People people;
    public User(){
        System.out.println("create User");
    }
}

People--(依赖)-->User--(依赖)-->People--(依赖)-->User.......,这就形成了循环依赖。

继续进入上篇的preInstantiateSingletons()方法:

 

 进行条件断点:

 

 

 

 进入上篇说的getSingleTon()方法:

 

 singletonObjects是spring的单例池,从其中没有拿到bean,singletonObject为null,且isSingletonCurrentlyInCreation()为false。

public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }

其实这个方法就是去判断该map(singletonCurrentlyInCreation)是否包含该bean?(这里是people)。

这个方法通俗意思就是 “该bean是否在创建过程中?”

先不管这个意思,继续往下走。

spring创建对象前还会做很多判断,例如是否为原型,是否抽象?

 

 这里的getSingleton(String beanName, ObjectFactory<?> singletonFactory)是重载,与之前的getSingleton(String beanName, boolean allowEarlyReference)不同。

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 (logger.isDebugEnabled()) {
                    logger.debug("Creating shared instance of singleton bean \'" + beanName + "\'");
                }
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<>();
                }
                try {
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                }
                catch (IllegalStateException ex) {
                    // Has the singleton object implicitly appeared in the meantime ->
                    // if yes, proceed with it since the exception indicates that state.
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        throw ex;
                    }
                }
                catch (BeanCreationException ex) {
                    if (recordSuppressedExceptions) {
                        for (Exception suppressedException : this.suppressedExceptions) {
                            ex.addRelatedCause(suppressedException);
                        }
                    }
                    throw ex;
                }
                finally {
                    if (recordSuppressedExceptions) {
                        this.suppressedExceptions = null;
                    }
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }

 

 

 

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

此方法把 “people”放入singletonsCurrentlyInCreation中,那么isSingletonCurrentlyInCreation("people")这时为true

进入lambda表达式 createBean()

create People Object ----注入依赖发现依赖User--->create User Object---发现依赖People---create People Object---发现isSingletonCurrentlyInCreation(beanName)为true,表示正在创建People:

 

 然后才会执行里面的代码:

 

 allowEarlyReference 是否允许从singletonFactories中通过getObject拿到对象,也就是执行if中的方法。

我们看一下singletonObjects(一级缓存),earlySingletonObjects(二级缓存),singletonFactories(三级缓存)。

AbstractAutowireCapableBeanFactory#doCreateBean()中:

 

 

 

 这时候存进去的并不是完整的bean:

 

 但是可以供User依赖注入了,这也就是spring对循环依赖的解决。

 

以上是关于Spring Boot源码:循环依赖的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码-循环依赖,Java架构师必学

Spring Boot (kotlin) 循环依赖

为啥我在 Spring-boot 应用程序中通过 SessionFactory 有循环依赖?

0源码基础学习Spring源码系列——Spring如何解决循环依赖

Spring Boot 2.6 + 集成 - internalPublisherAnnotationBeanPostProcessor 循环依赖

Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机