spring循环依赖

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里面保存

思考:

  1. 如果一个目标对象被aop动态加上事物增强功能(代理对象)的话,那么spring容器中存储的是目标对象,还是增强之后的对象,还是都存储?
    • 是spring只会存储一个对象,如果目标对象被aop产生的代理对象,那么存储的就是代理对象
  2. 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的初始化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值