Spring IOC循环依赖

本文探讨了Spring框架中的循环依赖问题,包括ClassA依赖ClassB,反之亦然,并深入剖析了Bean实例创建流程中的三级缓存机制。理解构造器和setter方法依赖,以及如何通过缓存避免循环依赖,对于Spring开发者至关重要。
摘要由CSDN通过智能技术生成

什么是循环依赖

ClassA中依赖ClassB
ClassB中依赖ClassA

依赖主要分为两种:引用、成员变量。
依赖注入(依赖)分为两种:构造方法、setter方法。

//订单
public class OrderService {
	@Autowired
	private UserService userService;
	
	public void saveOrder() {
		//插入订 单表(需要用户名称,而页面只传递一个用户ID)
		//调用UserService去查询用户信息
	}
}

//用户		
public class UserService {
	@Autowired
	private OrderService orderService;
	
	public void queryOrders() {
		//调用OrderService的服务
	}
}

Spring中Bean实例的创建流程

  • 实例化(new):此处通过反射调用构造器new对象,引处可能会发生循环依赖【构造器循环依赖】。无法通过自动解决,只能修改依赖关系或者改为setter方法依赖。
  • 填充属性:此处通过反射调用成员变量setter方法进行依赖注入,此处可能会发生循环依赖【setter方法循环依赖】。可能通过缓存解决。
  • 初始化:Bean初始化。

Spring三级缓存

源码级别描述
singletonObjects一级缓存用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用
earlySingletonObjects二级缓存存放原始的 bean 对象(尚未填充属性),用于解决循环依赖
singletonFactories三级缓存存放 bean 工厂对象,用于解决循环依赖

从缓存中获得bean顺序:

  • 先从一级缓存获得,没有则从二级缓存获得,没有则从三级缓存获得。

ClassA创建流程

  1. 实例化
    如果是单例bean,那么会创建ClassA对象并提前被暴露给三级缓存保存。
    实例化过程中只会bean创建出来,成员变量都是空值。

  2. 填充属性
    因为ClassA中有变量ClassB所以需要给ClassB变量赋值,此处从缓存中获得引用对象(现在缓存只有ClassA对象所以找不到)。
    则实例化ClassB对象并把ClassB添加到三级缓存。
    给ClassB填充ClassA对象,此时缓存中有ClassA对象,ClassB进行初始化。

  3. 初始化
    ClassA进行初始化。

在这里插入图片描述

注:每次添加缓存操作:添加二级缓存时先删除三缓存,添加一级缓存时会先删除二、三级缓存。

添加二级缓存代码:

在这里插入图片描述

添加一级缓存代码:
在这里插入图片描述

此时你会感觉二级缓存作用不大,如果把二级缓存删除仿佛也能正常注入,主要有两方面原因:

  • 三级缓存是bean的工厂,如果没有二级缓存那么每次从三级缓存获得出来的bean是不一样的。
  • 二级缓存存放的bean是未初始化完成状态,属于提前暴露bean。
  • 三级缓存也有提前暴露bean,还要对bean做beanPostProcessor后置处理。

思考

  • 如果一个目标对象被aop动态加上事务增强功能(代理对象)的话,那么spring容器中存储的是目标对象,还是增强之后的对象,还是都存储?
    答案是spring只会存储一个对象,如果目标对象被AOP产生了代理对象,那么存储的就是代理对象。

  • aop针对目标对象产生代理对象,是发生在bean创建的哪个流程呢?
    是发生在Bean初始化的过程中,具体说,是发生在Bean调用初始化方法之后,去进行AOP流程。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值