文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

spring循环依赖策略解析

2023-05-31 04:35

关注

循环依赖

所谓循环依赖就是多个Bean之间依赖关系形成一个闭环,例如A->B->C->...->A 这种情况,当然,最简单的循环依赖就是2个Bean之间互相依赖:A->B(A依赖B), B->A(B依赖A) 。在Spring中,如果A->B,那么在创建A的过程中会去创建B,在创建B(或B的依赖)的过程中又发现B->A,这个时候就出现了循环依赖的现象。

循环依赖的解决

spring中的循环依赖只有当

Bean是单例,
2.通过属性注入的情况

这两个条件满足的情况下是没问题的。但是如果是通过构造器依赖,或者不是单例模式的情况下循环依赖就会抛出异常BeanCurrentlyInCreationException。下面从代码层面上解析一下为什么。

Prototype的循环依赖问题

为什么最先介绍Prototype的循环依赖呢,因为可以顺便介绍在Spring中创建Bean的流程核心流程:在AbstractFoctory的doGetBean的方法。这个方法很长,这里只写出核心逻辑,并在注解上注明了个人理解:

protected <T> T doGetBean(    final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)    throws BeansException {    final String beanName = transformedBeanName(name);  Object bean;    //尝试获取单例对象,因为spring大部分的bean都是单例的,所以这里先尝试能否获取。  registered singletons.  Object sharedInstance = getSingleton(beanName);  //单例存在的情况下,那么beanName返回的肯定是单例类,但是这里还需要判断是不是FactoryBean  if (sharedInstance != null && args == null) {    ...    //FactoryBean应该返回getObject()对象    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);  }    else {    //走到这里,有可能beanName是单例模式,但之前并没有实例化,或者是Prototype类型。    //首先判断不是循环依赖,这里的循环依赖指的是Prototype类型    if (isPrototypeCurrentlyInCreation(beanName)) {      throw new BeanCurrentlyInCreationException(beanName);    }        try {      final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);      // 如果是单例,则创建单例模式      if (mbd.isSingleton()) {        // !!!这里是解决单例循环依赖的关键,后面再分析        sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {          @Override          public Object getObject() throws BeansException {            try {              return createBean(beanName, mbd, args);            }            catch (BeansException ex) {              throw ex;            }          }        });        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);      }        else if (mbd.isPrototype()) {        // 原型模式,则创建一个新对象.        Object prototypeInstance = null;        try {                        beforePrototypeCreation(beanName);              prototypeInstance = createBean(beanName, mbd, args);        }        finally {          //对应beforePrototypeCreation(),从map中移除              afterPrototypeCreation(beanName);        }        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);      }      ...    }  }    ...  return (T) bean;}

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 资料下载
  • 历年真题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯