Spring中循环依赖

来源:互联网 发布:java string 编码 编辑:程序博客网 时间:2024/06/08 18:34

Spring中bean的实例化方法主要是 prototype和singleton两种。其中singleton的循环依赖包括两种:构造器循环依赖,和setter的循环依赖。prototype中的循环依赖。

1.singleton 构造器循环依赖

代码示例:

public class CycleA {    private CycleB cycleB;    public CycleA(CycleB cycleB) {        this.cycleB = cycleB;    }    public void doSomething() {        System.out.println("this is the CycleA ... ");    }}public class CycleB {    private CycleC cycleC;    public CycleB(CycleC cycleC) {        this.cycleC = cycleC;    }    public void doSomething() {        System.out.println("this is the CycleB ...");    }}public class CycleC {    private CycleA cycleA;    public CycleC(CycleA cycleA) {        this.cycleA = cycleA;    }    public void doSomething() {        System.out.println("this is the CycleC ...");    }}

配置文件示例:

<bean id="cycleA" class="com.test.bean.blog.myCycleDependencies.bean.CycleA">        <constructor-arg name="cycleB" ref="cycleB"/>    </bean>    <bean id="cycleB" class="com.test.bean.blog.myCycleDependencies.bean.CycleB">        <constructor-arg name="cycleC" ref="cycleC"/>    </bean>    <bean id="cycleC" class="com.test.bean.blog.myCycleDependencies.bean.CycleC">        <constructor-arg name="cycleA" ref="cycleA"/>    </bean>

这个是一个Singleton构造器循环依赖的实例。构造器的循环依赖无法解决。CycleA依赖于CycleB,CycleB依赖于CycleC 。CycleC依赖于CycleA。在创建的时候,当构造CycleC的时候需要去创建CycleA。这个时候这个时候需要判断出发生了循环。
关键点:一、当创建CycleC的时候,需要创建CycleA,是在哪里被触发的。二、如何发现CycleA是一个循环依赖的。

  • 如何发现CycleA是一个循环依赖的

可以看一下代码:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {        Assert.notNull(beanName, "'beanName' 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<Exception>();                }                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 != NULL_OBJECT ? singletonObject : null);        }    }

以上代码是获取一个单例对象。首先Object singletonObject = this.singletonObjects.get(beanName); 获取到对应的bean。如果获取失败,就开始调用beforeSingletonCreation(beanName);开始创建。
代码如下:

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

其中由于CycleA在最开始创建的时候已经被写入到this.singletonsCurrentlyInCreation中了,这个beanName被写入到set中了。在创建过程中这个对象依赖到自身了,返回false。通过一个Set来记录下创建当前bean中依赖的bean。如果发现自己依赖自己就是一个循环依赖。

  • 当创建CycleC的时候,需要创建CycleA,是在哪里被触发的。

在通过CycleC的构造函数来创建bean的时候,发现会依赖CycleA的实例,这个时候首先创建CycleA的对象。具体代码如下:

protected BeanWrapper autowireConstructor(            String beanName, RootBeanDefinition mbd, Constructor<?>[] ctors, Object[] explicitArgs) {        return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);    }

将通过构造器来生成一个BeanWrapper的工作委托给ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs)。这个过程中需要将构造器中依赖的CycleA先实例化出来。
这里写图片描述
这个工作委托给BeanDefinitionValueResolver类中的public Object resolveValueIfNecessary(Object argName, Object value)方法
看下这个方法的实现由于在配置文件中定义了ref,在Spring内部被转换为RuntimeBeanReference对象:
这里写图片描述
具体的实现是通过BeeanFactory.getBean()来获取到所依赖的CycleA的实例。
具体如下第351行:
这里写图片描述

  • 总结
    以上就是Spring中单例构造器循环依赖的过程。在开始创建CycleA的时候,在准备实力化的时候将CycleA写到singletonsCurrentlyInCreation中,表示当前的bean对象开始实例化。
    然后开始创建的过程中,当将一个CycleA创建为一个BeanWrapper的时候,首先需要CycleA的构造函数中依赖的CycleB的对象,这个时候就开始创建CycleB,这个时候也会重复上面的过程将CycleB写到singletonsCurrentlyInCreation
    往复以上过程,又一次创建CycleA的时候,发现singletonsCurrentlyInCreation已经有了一个对象,表示一个对象循环依赖了。抛出异常。

2.prototype 循环依赖

代码示例还是之前的示例,将每个bean的scope改为prototype类型。
prototype循环依赖的处理过程如下,由于prototype只负责创建一个对象。循环依赖的判定逻辑是在创建CycleA的时候,发现依赖了CycleA,在多线程中,可能会出现这种情况,但是这种并不是循环依赖,所以使用ThreadLocal来隔离开不同的循环依赖。
在创建对象之前先检查是否是循环依赖了:
这里写图片描述
看下具体实现:
这里写图片描述
从ThreadLocal中获取到对应beanName是否在创建,如果在创建,就抛出异常。其中,当只有一个beanName的时候使用的String,当有多个beanName的时候存的是Set。

在创建之前将beanName的信息写到ThreadLocal中去:
这里写图片描述
和上面相同,需要判断是一个还是多个,多个需要将String转变为Set。

在创建完成的额时候需要将beanName从ThreadLocal中删除:
这里写图片描述

总结
prototype循环依赖主要是使用ThreadLocal来记录当前bean的依赖情况,创建之前先判断一下是否循环依赖,如果没有循环依赖将当前的beanName写到ThreadLocal中去。在创建完成的时候将当前beanName删除。

Singleton的setter循环依赖

相对于基于Singleton构造器循环依赖和prototype中判断当前bean是否正在创建set中,如果在就直接抛出异常。Singleton的setter循环依赖中判断是否是循环依赖也是用了和构造器相同的方法,但是将创建一个对象的过程拆分为两个步骤:initBeanpopuBeaninitBean:主要负责生成一个Bean的实例,这个实例中的属性可能还没有注入。popuBean向bean中注入属性,在获取属性的过程中可能会循环的去获取其他的bean。(Spring中对于属性的获取都是委托给BeanDefinitionValueResolver处理的。)
以 CycleA—> CycleB —> CycleC —> CycleA 。 这样一个循环依赖。这些加载的过程是如下过程:(注:initCycleA表示实例化CycleA;popuCycleA表示填充CycleA)。

这里写图片描述
以上:Spring在实例化的时候是一个递归的过程。在popuCycleA的时候,这个时候发起了initCycleB,然后开始popuCycleB,又递归的发起了initCycleC,然后popuCycleC,这个当中,由于CycleA已经初始化完成了,已经能够返回CycleA的实例。能够完成popuCycleC。然后递归的完成popuCycleB,然后完成popuCycleA。最终将所有的bean初始化完成。

Spring中在处理单例的时候所有的方法都是委托给DefaultSingletonBeanRegistry处理的。这个当中有三个关键的方法来帮助解决Spring中的循环依赖。

  • public Object getSingleton(String beanName)
    这个类是在BeanFactory.getBean最开始的地方调用的。
    这里写图片描述

按照注释,返回的实例是可能是一个完全实例化的bean也是一个为注入属性的bean。在DefaultSingletonBeanRegistry中不同的Bean将会被放在不同的容器中。这个后面再介绍。

  • public Object getSingleton(String beanName, ObjectFactory singletonFactory)

在这个方法中ObjectFactory中getObject方法提供了一个创建Bean的方法。

以上在createBeanean()是创建一个Bean的方法。createBean做了两件事,initBean和popuBean。在做这两件事情的中间调用了第三个接口

  • protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory)
    这里写图片描述
    如上图,这个方法调用的时机在initBean完成以后,在popuBean之前。这样在popuBean的过程中通过第一个方法获取到bean的实例的时候就能够获取到bean,而不用重新创建,触发循环校验的机制了。

Spring中单例的对象从创建到完成之间尽力的形态:
DefaultSingletonBeanRegistry中维护了三个Map来存放Bean
Map<String, Object> singletonObjects //缓存了所有的完全实例化成功的bean
Map<String, ObjectFactory<?>> singletonFactories //缓存了当前所有的ObjectFactory。这个ObejctFactorygetObject()中的方法是一个已经实例化的bean
Map<String, Object> earlySingletonObjects //这个bean中缓存的bean是一个已经实例化完成,但是还没有完全pop的bean。

总结
解决单例setter循环依赖的方式主要是将实例化bean的过程分为initBean 和popuBean过程,在这两个阶段之间调用一下第二个方法将bean注入到DefaultSingletonBeanRegistry中去。这样在循环依赖的时候就能够获取到依赖的对象的引用,而不用在一次去再一次initBean,发生循环依赖。

ObjectFactory这个接口是DefaultSingletonBeanRegsitry提供的一个获取bean的策略,这样能够使得类更加的通用。

原创粉丝点击