什么是循环依赖

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流程。


版权声明:本文为h273979586原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/h273979586/article/details/122896552