互联网架构-Spring5.0源码深度解析-026:SpringBean循环依赖问题解决方案

1 SpringBean的循环依赖任务安排

课程内容:

  1. 什么是Spring的循环依赖?循环依赖会存在那些问题
  2. Spring循环依赖在单例与多例的情况下有那些区别
  3. 使用三级缓存解决Spring循环依赖问题

2 SpringBean的循环依赖基本概念

Spring核心:SpringIOC和AOP概念、依赖注入(赋值)

什么是Spring循环依赖问题
A 对象中的属性B依赖于B对象,B对象中属性A依赖A对象
在这里插入图片描述
注意只有在bean对象是单例的情况下,Spring才会去解决循环依赖问题(三级缓存);
bean对象如果是多例的情况,因为设置注入的多例对象不明确,就会产生循环依赖问题(不断死循环创建对象,程序抛出异常)。
在这里插入图片描述
代码验证单例/多例情形循环依赖问题

@Configuration
@ComponentScan("com.mayikt.service")
public class MyConfig {
}
@Service
//@Scope("prototype")
public class AService {
    // AService创建的时候,要等BService先创建
    @Autowired
    public BService bService;
}
@Service
//@Scope("prototype")
public class BService {
    @Autowired
    public AService aService;
}
public class SpringApp {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        AService aService = annotationConfigApplicationContext.getBean("AService", AService.class);
        BService bService = annotationConfigApplicationContext.getBean("BService", BService.class);
    }
}

运行结果:
在这里插入图片描述
放开多例注释,运行结果:
在这里插入图片描述

3 SpringBean多例如何解决循环依赖问题

思考问题:如果项目对象必须要是多例且必须要循环引用,如何解决?
明确指定引用哪个对象

@Service
@Scope("prototype")
public class AService {
    // AService创建的时候,要等BService先创建
//    @Autowired
    public BService bService;

    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) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        AService aService = annotationConfigApplicationContext.getBean("AService", AService.class);
        BService bService = annotationConfigApplicationContext.getBean("BService", BService.class);
        aService.setBService(bService);
        bService.setAService(aService);
    }
}

运行结果:
在这里插入图片描述

4 SpringBean循环依赖三级缓存概念

分析spring单例底层如何解决循环依赖问题
单例对象在ioc容器被加载的时候创建,多例的情况下是在调用的时候创建。

SpringBean中 AService对象被创建流程步骤:

  1. doGetBean创建bean对象
  2. getSingleton (beanName) 获取缓存对象
    singletonObjects 一级缓存完整对象(对象已经实例化成功并且所有属性都已经赋值)
    earlySingletonObjects 二级缓存,缓存婴儿对象
    singletonFactories 三级缓存,存放婴儿对象
    在这里插入图片描述

5 SpringBean循环依赖源码分析

理解概念:
完整对象:该对象实例化完成并且所有的属性已经赋值。
婴儿对象(提前对象):已经实例化完成但是属性没有赋值。

  1. 走doGetBean方法的else分支,调用getSingleton(String beanName, ObjectFactory<?> singletonFactory)
    this.singletonsCurrentlyInCreation.add(beanName) 添加标记,表示该对象已经开始创建
    在这里插入图片描述
  2. createBean() →doCreateBean
  3. addSingletonFactory将婴儿对象(不完整对象,只是实例化完成但是属性没有赋值) 存放三级缓存中;
    在这里插入图片描述
  4. A对象已经存放到三级缓存中,开始给对象属性赋值的时候需要创建B对象。创建B对象的时候调用getBean方法,也把B对象放入三级缓存中,同样给B属性赋值的时候需要依赖A。此时从三级缓存中获取A(不完整)给B赋值,B变成完全对象,再给A赋值A也变成完整对象。
    在这里插入图片描述

6 Spring循环依赖Bean对象引用问题

public class SpringApp {
    public static void main(String[] args) {
        // 缓存婴儿对象
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("aService",new AService());
        stringObjectHashMap.put("bService",new BService());
        // 从缓存中查询到赋值
        AService aService = (AService) stringObjectHashMap.get("aService");
        BService bService = (BService) stringObjectHashMap.get("bService");
        // java的引用传递
        aService.setBService(bService);
        bService.setAService(aService);
    }
}

在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值