Spring5.0源码深度解析之SpringBean循环依赖问题解决方案

Spring循环依赖

什么是Spring的循环依赖?循环依赖会存在哪些问题?

示例:AService依赖BService; BService依赖AService

@Service
public class AService {
    //
    @Autowired
    public BService bService;
}
@Service
public class BService {
    @Autowired
    public AService aService;
}

f44ff58a3bca2bcec80361be9cadd3ab684.jpg

上面演示的例子就是循环注入

如果改为多例的化,运行时就会报错,循环引用异常,找不到对象

@Scope("prototype")

a94f61277b8779970dd3957bae6f6d34987.jpg

Spring中的循环依赖问题在单例的情况下,Spring是已经帮我们解决好了,多例没有解决循环依赖问题。

为啥,多例的情况下 Spring没有去解决循环依赖问题?

因为在多例的情况下,设置的多例的对象没有明确哪一个,就会产生循环依赖问题。

Spring多例我们要:如何解决循环依赖问题?

我们可以自己去:明确指定引用那个对象

@Service
@Scope("prototype")
public class AService {
   // @Autowired
    public BService bService;
    // 为什么Aservice在创建的时候 为什么Bservice比ASERVICE 先创建
    public AService() {
        System.out.println("AService被Java的反射技术创建");
    }
    public void setbService(BService bService) {
        this.bService = bService;
    }

}
@Service
@Scope("prototype")
public class BService {
   // @Autowired
    public AService aService;

    public void setaService(AService aService) {
        this.aService = aService;
    }
}
public class SpringApp {
    public static void main(String[] args) {
//        1. ioc容器在创建的时候所有的单例对象是不是会被创建
       AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
//        // 对例子情况 当你在调用的时候才获取
        AService aSerivce = applicationContext.getBean("AService", AService.class);
        BService bSerivce = applicationContext.getBean("BService", BService.class);
        aSerivce.setbService(bSerivce);
        bSerivce.setaService(aSerivce);
        // 循环引用异常 找不到对象
        /**
         * 思考问题? 如果我们的项目对象必须要是多例? 而且必须要循环引用  明确的指定引用那个对象
         */
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (int i = 0; i < beanDefinitionNames.length; i++) {
            System.out.println(beanDefinitionNames[i]);
        }

c7f0d2bf182fe39c23094482bdca7ee93a9.jpg

SpringBean循环依赖三级缓存概念

思考问题:单例对象在什么时候创建?

在IOC容器被创建的时候创建

多例的情况下,是在getbean()调用的情况下创建。多例对象每次用完就会去销毁掉。

SpringBean Aservice对象被创建流程步骤源码分析

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);

64ea24b3267dcfc798d06d4c1ae8841f389.jpg

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

0e6303b3e281e2712716e67fc64367f6256.jpg

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

d14983512170eebd10b49eb0f1694bdcfc8.jpg

public Object getSingleton(String beanName) {
    return this.getSingleton(beanName, true);
}

获取缓存对象:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);    //根据BeanName去集合中查,查到就返回这个对象,【】【】【】一级缓存对象集合【】【】【】缓存完整对象【】【】完整对象表示对象已经创建完了,并且对象属性已经赋值了。
    if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
        Map var4 = this.singletonObjects;
        synchronized(this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);    //查询二级缓存中是否有缓存对象
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);    //查询三级缓存,三级缓存中有的化,将三级缓存中的数据放入二级缓存中
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

0835afccfc11bbfe8f2d31223ef736340de.jpg

9264e7d0fec57033dadf0b35c2ed9ff3c1a.jpg

一级缓存没有找到,就去找二级缓存中找

04bed1b8d511aee68fecbc31a0b22c8eb97.jpg

singletonObject == null && this.isSingletonCurrentlyInCreation(beanName) //一级缓存没有,并且singletonsCurrentlyInCreation判断是否之前标记为该对象开始创建

fde14e267eb582a2eebb4525cdac768d4f0.jpg

4058a349dff5ad1b25ef31a5376d5a6a5ea.jpg

if (isPrototypeCurrentlyInCreation(beanName)) { //我们对象是单例的,所有不进入
   throw new BeanCurrentlyInCreationException(beanName);
}

c9da1ed77ba69fb98b830e925713a2c04be.jpg

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

4f77c957b07e6e7f361e37559cb71e934a2.jpg

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

标识为该对象开始创建

957bdc3f2703474862ff2876d4a6f994cf8.jpg

最终调用

180e8be65fb08ad2d99c103d89d10fb1224.jpg

正真去创建我们的Bean对象:

7aee7c98d9333fde084d719b7ed95980749.jpg

既然要创建对象,先反射走无参构造函数,对象先实例化完成,在赋值

724a043018d8ac9cdbd8f5f40d1188ac77f.jpg

执行这个方法,输出构造函数打印的语句,说明底层通过Java反射机制初始化的

1349047007de37faf6b98f9e6d8cfeadec9.jpg

在这之前,我们的对象属于婴儿对象,因为它的属性还没有赋值。都是称为婴儿对象。

那么什么时候赋值呢?

d01d0489f4ff26544296fba1f10fc95e0f2.jpg

populateBean(beanName, mbd, instanceWrapper);//这里给对象属性赋值

在给对象属性赋值之前:

4e87b6d4c6e81024934ee23934a594e8c4d.jpg

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
      if (!this.singletonObjects.containsKey(beanName)) {    //【】【】如果一级缓存没有该对象的情况下,会将该对象存放在三级缓存中
         this.singletonFactories.put(beanName, singletonFactory);    //【】【】存放在三级缓存中,对象实例化完成,但是没有赋值,婴儿对象【】【】
         this.earlySingletonObjects.remove(beanName);
         this.registeredSingletons.add(beanName);
      }
   }
}

1f2632b9f5765759f2677132d4d7c8b3c89.jpg

c689f1d1087f15e21c584479c2afc13378a.jpg

A对象坚持依赖B对象,这时候B对象也需要被创建

A对象已经存放在三级缓存中,这时候要去创建B对象

此时B对象也要走A对象流程

875678c3eb382f9085c1b56fa43f4c6b0d2.jpg

看下调用链

2c27b46c699953a0726c1f4a712285422fa.jpg

01a2a826cf368b52547da33b580bb58b7b6.jpg

c4084c155de571ffcc2f1f3fbe27ebb9a7f.jpg

也将B对象放入三级缓存

93db1ffe53e1cf669feee5cd22fa370731c.jpg

3486e1edfbbaab2dc8e21b47b498ed51371.jpg

总结下:

AService在创建的时候,提前曝光存放到三级缓存中,AService发现依赖BService,这时候Bservice提前曝光存放到三级缓存中去。

此时BService又依赖AService,此时BService经过赋值是完整对象,但是Aservice还是婴儿对象,没有完全创建完毕。

就会去把BService对象注册到一级缓存中,同时会把之前缓存BService对象的二级缓存清除掉

AService对象依赖BService,BService此时已经创建成功了,那么AService在设置属性后,就直接把BService赋值给AService。

开始注册AService对象

07df63d3c486643fd3ebe775f153caa1dc8.jpg

c9bcf06f129e28e19f2467f85206fefcfe7.jpg

总结:

 SpringBean中 Aservic对象被创建流程步骤源码分析:

  1. doGetBean创建我们bean对象
  2. getSingleton (beanName) 获取缓存对象

注意:完整对象概念:对象已经实例化成功并且所有属性都已经赋值

  • singletonObjects 一级缓存完整对象
  • earlySingletonObjects 二级缓存 缓存婴儿对象
  • singletonFactories 三级缓存存放婴儿对象

理解概念:

  1. 完整对象表示该对象实例化完成并且所有的属性已经赋值。
  2. 婴儿对象(提前对象)对象已经实例化完成但是属性没有赋值的。

singletonObject ==null&&this.singletonsCurrentlyInCreation.contains(beanName);

{

才能够查询二级缓存

}
singletonsCurrentlyInCreation :标记为该对象开始创建

  1. getSingleton(String beanName, ObjectFactory<?> singletonFactory)

this.singletonsCurrentlyInCreation.add(beanName) 表示该对象已经开始创建

  1. createBean() →doCreateBean
  2. addSingletonFactory  将婴儿对象(不完整对象也就是只是实例化完成但是属性没有赋值的) 存放三级缓存中。
  3. A对象已经存放到三级缓存中,开始给对象属性赋值的时候 需要创建B对象。

A对象检查发现依赖B对象 这时候B对象也需要被创建

本文参考:

蚂蚁课堂

http://www.mayikt.com/

 

转载于:https://my.oschina.net/u/3995125/blog/3081862

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值