spring循环依赖

spring中依赖注入的方式

  • set注入
  • 构造器注入
  • 工厂注入

循环依赖主要发生在bean生命周期中的这个部分
在这里插入图片描述

  • 构造注入产生的循环依赖发生在实例化阶段,这个spring并不能解决这个问- 题。
  • set注入则发生在populateBean阶段。

spring 并不能解决所有场景的循环依赖,解决场景主要如下图
在这里插入图片描述
为了解决循环依赖,它引入了三级缓存的方式,三级缓存主要是这三级:

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

/** Cache of early singleton objects: bean name --> bean instance */
/** 这里的bean既可以是没有被增强过的单例,也可以是被动态代理的单例,就看一级缓存中的ObjectFactory是什么了 */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

假如有两个单例的bean,testService1和testService2,spring在创建时的大致流程如下
在这里插入图片描述
这个流程中,在一级缓存获取不到实例,那么就会创建一个bean实例,但是此时是原生的,没有被代理的,如果这个bean是单例,且容器允许循环依赖,且当前正在创建中,且允许被提前暴露,那么这时会将bean以及创建bean的aop代理的引用(如果感知到是由aop的)传入以返回一个ObjectFactory对象,然后存放到三级缓存中。

  • 对于单例的循环依赖,这个流程就可以完美解释是如何解决的。但同时,在解决循环依赖问题上,好像二级缓存并没有存在感,那么是不是可以不要二级缓存,当然不可以,上边已经列出来了二级缓存保存的东西,是实例化好的bean,这里的实例化,不仅是指原生的对象,还有被spring管理的动态代理的对象,而动态代理的实现,则是一级缓存中的ObjectFactory保存的创建方法,所以如果没有二级缓存,或者说使用两级缓存来处理循环依赖,那么spring的增强就无法实现,或者是spring就无法做到原生bean和代理对象的兼容

  • 对于多例的循环依赖,因为每次实例化后注入属性都是新创建一个对象,而且不会放入到缓存,所以自然就无法处理,形成死循环

  • 对于构造器注入,每次实例化就需要注入,根本就找不到bean,自然就死循环了

  • 对于单例的代理对象的set注入,如下

@Service
publicclass TestService1 {

    @Autowired
    private TestService2 testService2;

    @Async
    public void test1() {
    }
}
@Service
publicclass TestService2 {

    @Autowired
    private TestService1 testService1;

    public void test2() {
    }
}

spring的流程大致如下
在这里插入图片描述

因为testService1中有个异步方法,所以spring-aop会自动给它生成一个代理对象,而这个代理对象是testService2在依赖testService1时,根据三级缓存中的增强方法创建的,和最后testService1注入testService2后生成的代理对象不一样,所以导致不相等,但是如果是@Async方法是在testService2中的话,则不会有问题,因为spring加载bean的时候,加载顺序是会根据bean的name来的

各种解决方案

  • 生成代理对象产生的循环依赖
    这类循环依赖问题解决方法很多,主要有:

    • 使用@Lazy注解,延迟加载
    • 使用@DependsOn注解,指定加载先后关系
    • 修改文件名称,改变循环依赖类的加载顺序
  • 使用@DependsOn产生的循环依赖
    这类循环依赖问题要找到@DependsOn注解循环依赖的地方,迫使它不循环依赖就可以解决问题

  • 多例循环依赖
    这类循环依赖问题可以通过把bean改成单例的解决。

  • 构造器循环依赖
    这类循环依赖问题可以通过使用@Lazy注解解决

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值