目录
前言:
今天聊一聊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下的循环依赖解析
自己注入自己不会报错