spring循环依赖
- 依赖:引用、成员变量
- ClassA类---->ClassB类 ClassB类---->ClassA类
- 依赖注入有两种注入方式:构造方法\setter方法注入
循环依赖分为
- 构造方法
- setter方法
循环依赖的例
//订单
OrderService {
UserService userService;
saveOrder(){
//插入订单表(需要用户名称、而页面只传递一个用户ID)
//调用UserService去查询用户信息
}
}
//用户
UserService{
OrderService orderService;
queryOrders(){
//调用OrderService的服务
}
}
Spring中解决setter方法产生的循环依赖问题是通过三级缓存来解决的?
- singletonObjects:第一级缓存
- key:beanName
- value是成品的bean实例
- earlySingletonObjects:第二级缓存
- key是beanName
- value是半成品的bean实例对象
- singletonFactories:第三级缓存
- key是beanName
- value是提早产生Bean实例的对象工厂ObjectFactory
三级缓存获取对象的顺序
- 先从一级缓存中获取对象(ObjectFactory获取对象,有可能获取的是代理对象),将获取到的对象,放入二级缓存
- 三级缓存中没有再从二级缓存中获取对象
- 再没有,从三级缓存中获取对象
三级缓存添加对象的顺序
- 先将第一步new出来的对象,添加到三级缓存中的ObjectFactory里面保存
思考:
- 如果一个目标对象被aop动态加上事物增强功能(代理对象)的话,那么spring容器中存储的是目标对象,还是增强之后的对象,还是都存储?
- 是spring只会存储一个对象,如果目标对象被aop产生的代理对象,那么存储的就是代理对象
- aop针对目标对象产生代理对象,是发生在bean创建的那个流程?
- 是发生在bean初始化的过程中,具体说,是发生在bean调用初始化方法之后,去进行aop流程。
spring中bean实例的完整创建流程
- Bean的实例化(new)------------------此处会反射调用构造器去new对象,所以说此处有可能会发生【构造器循环依赖】
- 此处产生的【构造器循环依赖】无法自动解决,只能修改依赖关系或者改为setter方法去依赖
-
//订单 OrderService { UserService userService; public OrderService(UserService userService){ this.userService=userService; } saveOrder(){ //插入订单表(需要用户名称、而页面只传递一个用户ID) //调用UserService去查询用户信息 } }
注意:
-
此时从java本身来说,Bean实例对象已经new出来了,可以正常使用了。
-
但是从Spring来说,该bean必须完成三个步骤之后,才认为可以被人正常使用。
-
-
Bean的属性填充(setter)-------此处会对成员变量调用setter方法去进行依赖注入。---此处可能发生【setter方法循环依赖】
-
其实此时bean实例已经存在了,只是没有对外暴露使用而已
-
Spring的单例bean被创建成功之后,会放入SingleObjects的Map集合中,对外暴露使用
-
可以使用缓存的方式去解决循环依赖问题
-
ClassA{ ClassB } ClassB{ ClassA }
创建ClassA的流程
-
实例化
-
属性填充---给ClassB赋值(getBean---去ioc容器找到)----
-
如果此时还找不到ClassA,那么又会从第一步开始了,那这样就形成死循环了。为了不让死循环,那么我们需要此时ClassA的实例被找到;SingletonObjects集合中不存放半成品,所以需要一个新的Map集合来存储半成品(第二级缓存);为了保证提前暴露的对象,和最终的对象是一个,我们需要在获取这个提前暴露的对象的时候,也需要判断是否进行提前代理;那么这个时候,我们就需要一个三级缓存。(beanName,获取一个ObjectFactory的工厂类,该类就可以添加产生代理对象的逻辑);如果是单例bean,并且允许应用、该beanName存储到singletonsCurrentlyInCreation(set集合),那么ClassA对象会提前暴露给三级缓存保存。
-
ClassB实例化
-
ClassB属性填充---ClassA类型变量赋值(getBean)
-
ClassB初始化
-
ClassB放入SingleonObject集合中(才是对外暴露的引用集合)
-
-
-
ClassA初始化
-
ClassB放入SingleonObject集合中(才是对外暴露的引用集合)
-
-
-
Bean的初始化