spring之循环依赖底层源码分析

发布时间:2024年01月05日

目录

前言:

@Resouce / @AutoWired区别

@Resouce注入过程

spring循环依赖底层原理源码解析

解决循环依赖问题所需要的重要关键对象

循环依赖不同场景解决方式


前言:

? ? ? ?今天聊一聊spring循环依赖问题,同时分析一下@Resouce / @AutoWired区别。


@Resouce / @AutoWired区别

? ? ? @Autowired注解是Spring提供的,而@Resource注解是J2EE本身提供的

? ? ? @Autowird注解默认通过byType方式注入,而@Resource注解默认通过byName方式注入

? ? ? @Autowired注解注入的对象需要在IOC容器中存在,否则需要加上属性required=false,表示忽略当前要注入的bean,如果有直接注入,没有跳过,不会报错。

? ? ?@Autowired是通过 AutowiredAnnotationBeanPostProcessor 来实现的

? ? ?@Resouce 是通过 CommonAnnotationBeanPostProcessor 来实现的


@Resouce注入过程

1. 寻找标记了@Resouce注入点

? ? ? ?包括从字段或方法上查找,符合条件的会生成ResourceElement对象,最后将找到的所有标记了该注解的注入点放到LinkedList集合中。

2. @Resouce属性值注入,遍历每个注入点进行注入

? ? ? ? 2.1 如果使用@Resouce时没有指定具体的name,那么则用field的name,或setxxx()中的xxx。拿属性的名字去BeanFactory中有没有该bean,如果有直接返回。如果@Resouce指定了name那么就按照name去getBean,如果找不到就是找不到。

? ? ? ? 2.2 如果没有指定name并且拿属性的名字去BeanFactory中有没有该bean,则继续判断属性上标记了@Lazy注解,如果会直接返回一个代理对象注入给属性。如果没有得话会和@Autowired注解得工作原理一样,先byType再byName。


spring循环依赖底层原理源码解析

假设场景:

? ? ? ? AService的Bean对象内部包含BService对象

? ? ? ? BService的Bean对象内部包含AService对象

? ?AService出现了循环依赖的情况下,需要提前进行AOP,如何才能知道是否出现了循环依赖呢?

? ? ? ?在Bean一开始创建的时候给一个属性用来记录当前bean是否还在创建中。通过判断是否还在创建中确定是否出现循环依赖问题。

先创建AService,执行AService的生命周期
0. singletonCurrentlyInCreation:在一开始创建的时候记录bean的创建状态
1. 实例化AService-->得到一个对象--SMap<AService:  Lambda(AService原始对象)>
    根据原始对象生成一个Lambda表达式
2. 填充BService属性 -- > 去单例池找BService-- >再去SMap去找--> 没有则创建BService
3. 填充其他属性/填充CService属性
4. 初始化前、初始化
5. 初始化后
6. 放入单例池


创建BService,执行BService的生命周期
2.1. 实例化BService-->得到一个对象-->存入SMap<BService: BService原始对象>
2.2. 填充AService属性
-- > 去单例池找AService(一级缓存 )
-- >singletonCurrentlyInCreation(判断是否正在创建)
-- >正在创建得话就出现了循环依赖
-- >earlySingletonObjects(二级缓存中去找是否有 AOP代理对象)
-- >如果没有就通过三级缓存的Lambda表达式提前进行AOP
-- >得到AService代理对象
-- >放入二级缓存中
如果不需要进行AOP就将三级缓存中原始对象放入二级缓存,并且会移除对应三级缓存内容
2.3. 填充其他属性
2.4. 初始化前、初始化
2.5. 初始化后
2.6. 放入单例池


创建CService,执行CService的生命周期
3.1. 实例化CService-->得到一个对象-->存入SMap<CService: CService原始对象>
3.2. 填充AService属性 
-- > 去单例池找AService
-- > 没找到则判断singletonCurrentlyInCreation是否正在创建
-- >如果正在创建则表示出现循环依赖问题
-- >去二级缓存中去找
-- >因为创建了BService所以在二级缓存中可以找到,就返回AService代理对象。
3.3. 填充其他属性
3.4. 初始化前、初始化
3.5. 初始化后
3.6. 放入单例池

注意:添加CService是为了解决可能出现的问题,如果判断出当前需要进行AOP就去创建代理对象的话,那么BService会创建一个代理对象,CService也会创建一个代理对象。保证生成对象单例。

解决循环依赖问题所需要的重要关键对象

三级缓存:

? ? ? 1.singletonObjects:单例池(一级缓存),存放经过完整生命周期的bean

? ? ? 2.earlySingletonObjects: 二级缓存,存放的是未经过完整生命周期的bean对象,比如原始对象或提前进行AOP的对象。 存放的就是三级缓存执行后的结果。

? ? ? ?3.singletonFactories:SMap 表达式中存放的是一段逻辑,这个逻辑会判断到底返回原始对象还是代理对象。

? ? ? ? Lambda表达式中有beanName、beandefinition、bean(原始对象)

额外:

? ? ? ?1. singletonCurrentlyInCreation:在一开始创建的时候记录bean的创建状态

? ? ? ?2. earlyProxyReferences:用来记录某个原始对象是否进行过AOP 了。

循环依赖不同场景解决方式

1. 原型bean情况下的循环依赖解析

? ? ? ? 不能解决

2. 构造方法导致的循环依赖解析

? ? ? ? @Lazy

3. @Async情况下的循环依赖解析

? ? ? ?使用@Async会异步生成一个代理对象,使用@Lazy注解直接生成代理对象返回,在异步使用的时候会根据name去找代理对象, 此时找到的bean与@Lazy注解生成的bean是同一个。

4. @Transaction情况下的循环依赖解析

不会报错,因为@Async是新添加了一个BeanPostProcessor 而 @Transaction添加的是advisor

5. BeanFactoryAware下的循环依赖解析

? ? ? ? 自己注入自己不会报错

文章来源:https://blog.csdn.net/m0_61853556/article/details/135343654
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。