循环依赖的底层原理(三级缓存)
@Component("bService")
public class AService {
//aservice的生命周期 1实例化(new AService)2填充bService属性3填充其他属性4aop5放入单例池
// 不是所有的对象都叫bean,只有经历了spring的所有步骤才能叫做bean
@Autowired
private BService bService;
public void test(){
System.out.println(bService);
}
}
@Component("aService")
public class BService {
@Autowired
private AService aService;
}
aservice的生命周期: 1实例化(new AService)原始对象 2填充bService属性---》从单例池中查找----》找不到----》创建BService 1. 实例化(new BService) 2. 填充aService属性---》从单例池中查找----》找不到----》创建aService 3. 填充其他属性 4. aop 5. 放入单例池 bean对象 3填充其他属性 4aop 5放入单例池 bean对象
这样就是循环依赖,我们就需要使用map来解决这个问题
aservice的生命周期: 1实例化(new AService)原始对象---》LLMap<aservice,aservice对象> 2填充bService属性---》从单例池中查找----》找不到----》创建BService 1. 实例化(new BService) 2. 填充aService属性---》从单例池中查找----》从LLMap找----》找到aservice原始对象 3. 填充其他属性 4. aop 5. 放入单例池 bean对象 3填充其他属性 4aop 5放入单例池 bean对象
我们使用一个map来存放aservice对象,在2.2的时候从map中找到aservice对象,就打破了这个依赖循环。
这样表面上也有一个问题,这个aservice对象看起来并没有赋值,但是其实是会有的,因为我们一直是在引用这个aservice的内存地址,那么它就会执行生命周期的动作。
本来是是原始对象,但是我们要代理对象,这时候我们就得提前进行aop得到代理对象
判断是否出现了循环依赖-----》提前进行AOP aservice的Bean生命周期: 0 creatingSet.add<'aService'> (正在创建中的bean ) 1实例化(new AService)原始对象---》 2填充bService属性---》创建BService 1. 实例化(new BService) 2. 填充aService属性---》从单例池中查找----》找不到----》aservice正在创建中?---》aservice出现了循环依赖---》AOP---》aservice代理对象 3. 填充其他属性 4. aop 判断是否提提前执行AOP Aservice代理对象 5. 放入单例池 bean对象 3填充其他属性 4aop 5放入单例池 bean对
判断是否出现了循环依赖-----》提前进行AOP aservice的Bean生命周期: 0 creatingSet.add<'aService'> (正在创建中的bean ) 1实例化(new AService)原始对象---》 2.1填充bService属性---》创建BService 1. 实例化(new BService) 2. 填充aService属性---》从单例池中查找----》找不到----》二级缓存找---》找不到---》aservice正在创建中?---》aservice出现了循环依赖---》AOP---》aservice代理对象---》放入二级缓存 3. 填充其他属性 4. aop 判断是否提提前执行AOP Aservice代理对象 5. 放入单例池 bean对象 2.2填充cService属性---》创建cService 1. 实例化(new cService) 2. 填充aService属性---》从单例池中查找----》找不到---》第二级缓存---》aservice代理对象 3. 填充其他属性 4. aop 判断是否提提前执行AOP Aservice代理对象 5. 放入单例池 bean对象 3填充其他属性 4aop 判断是否提提前执行AOP Aservice代理对象 4.5earlySingletObjects .get('aservice')--->aservice 代理对象 5放入单例池 bean对 6 creting,remove(’aservie‘)
二级缓存:earlySingletObjects Map<BeanName,baen> 也是用来解决bean的单例
一级缓存:单例池 singletonObjects储存对象 Map<beanName,bean>
一级缓存中的对象是经历了所有的生命周期的,二级缓存是没有的,但是两个缓存中的对象是同一个对象,因为是单例对象
AOP的代理逻辑
当我们进行aop的时候就得需要有对象的原始对象
判断是否出现了循环依赖-----》提前进行AOP aservice的Bean生命周期: 0 creatingSet.add<'aService'> (正在创建中的bean ) 1实例化(new AService)原始对象---》 LLMap<'aservice',lambda(()->getEarlyBeanReference(beanName,mbd,bean))> 2.1填充bService属性---》从单例池中找--》找不到---》创建BService 1. 实例化(new BService) 2. 填充aService属性---》从单例池中查找----》找不到----》二级缓存找---》找不到---》aservice正在创建中?---》aservice出现了循环依赖---》三级缓存通过lambda---》拿到aservice原始对象--》AOP---》aservice代理对象---》放入二级缓存 3. 填充其他属性 4. aop 判断是否提提前执行AOP Aservice代理对象 5. 放入单例池 bean对象 3填充其他属性 4aop 判断是否提提前执行AOP Aservice代理对象 4.5earlySingletObjects .get('aservice')--->aservice 代理对象 5放入单例池 bean对 6 creting,remove(’aservie‘)
lambda(()->gettarlyBeanReference(beanName,mbd,bean))
beanNanem:名字
mbd:beanDefinition
bean:对象
将这个lambda作为第三级缓存的val,三级缓存存储的是<'对象名',lambda(()->gettarlyBeanReference(对象名,beanDefinition,bean对象))>
三级缓存:用来进行兜底的,存储单例对象。
单例池 一级缓存 :保存单例对象 保存经过了完整Bean生命周期的对象
二级缓存:出现了循环依赖提前来保存没有经历完整Bean生命周期对象的。
大部分情况,都是单例的bean,都会把单例bean存到addSingletonFactory的singletonFaction Map中也就是三级缓存。
一个对象出现了循环依赖都能在三级缓存中找到对象。
在填充出现循环依赖的bean对象时:
从单例池中找-->找不到再到二级缓存中找-->找不到再到3级缓存中找(只要是单例bean就能找到)-->aop-->生成代理对象-->放入二级缓存中.
单例池是ConcurrentHashMap。
(ConcurrentHashMap详解:线程安全的HashMap,1.7之前是使用分段式锁,将数据分之后采用了C成一段一段储存,给每一段数据配一把锁,也就是segment,不会扩容,最多支持16个线程并发写。1.8之后采用了CAS和synchroized方式处理并发。CAS确定Key的数组下标,synchroized保证链接点的同步效果。也有红黑树。)
二级缓存中放入的同时,需要在一级缓存中释放,就得保证事物的原子性,所以一级缓存和二级缓存就不不要使用ConcurrentHashMap,因为只需要给它们加锁即可实现。
gettarlyBeanReference(beanName,mbd,bean)得到提前bean的引用(原始对象)
提前进行AOP
这里判断是否有提前进入过AOP。
如果提前进行了AOP,就给它存储原始对象,这里判断是否进入AOP的就remove这个对象,看它得到是否是这个bean对象(remove和put不同,remove的返回值就是当前的key对应的value.),如果是那就不再进行aop,表示提前进行了AOP。
当两个对象互相依赖的时候,就产生了循环依赖,在不是构造方法的情况下,
1先将正在创建的a对象放入creatingSet中,实例化对象,将原始对象放入singletFactrys<对象名,存放对象名,beanDefinition和对象的lambda表达式>的三级缓存,返回对象。
2填充另一个b对象的属性(
2.1实例化
2.2填充a的属性 从singletonObjects 单例池中找 找不到就到earlysingletonObjects 二级缓存中找 找不到 判断a是否在创建中,出现循环依赖 在三级缓存中拿到a原始对象 aop得到a代理对象 放入二级缓存中(同时在一级缓存中释放)
2.3 填充其他属性
2.4 advicedBeans判断是否提前进行了AOP 得到代理对象
2.5 放入一级缓存 代理池中
)
3 填充其他属性
4 advicedBeans判断是否提前进行了AOP 得到代理对象
4.1 二级缓存中 earlySingletObjects.get(’a‘) 得到代理对象
5 放入单例池 bean对象
6 cretingSet.remove(’a‘)
是不是可以解决所有循环依赖?
@Component("aService") public class BService { private AService aService; public BService(AService aService ){ this.aService = aService; } } @Component("bService") public class AService { //aservice的生命周期 1实例化(new AService)2填充bService属性3填充其他属性4aop5放入单例池 // 不是所有的对象都叫bean,只有经历了spring的所有步骤才能叫做bean private BService bService; public AService(BService bService) { this.bService = bService; } }
并不能。
@Component("bService") public class AService { //aservice的生命周期 1实例化(new AService)2填充bService属性3填充其他属性4aop5放入单例池 // 不是所有的对象都叫bean,只有经历了spring的所有步骤才能叫做bean private BService bService; @Lazy public AService(BService bService) { this.bService = bService; } } @Component("aService") public class BService { private AService aService; @Lazy public BService(AService aService ){ this.aService = aService; } } public static void main(String[] args) { UUService uuService = new UUService();//原始对象 ProxyFactory proxy = new ProxyFactory(); proxy.setTarget(uuService);//传入原始对象 proxy.addAdvice(new MethodBeforeAdvice() { public void before(Method method, Object[] objects, Object o) throws Throwable { //method表示当前执行的方法,objects是方法的参数,o表示tager类 System.out.println("执行目标方法调用之前的逻辑"); method.invoke(o,objects); } }); UUService uuService1 = (UUService) proxy.getProxy(); uuService1.test(); } 执行目标方法调用之前的逻辑 类自带的方法 类自带的方法
在有参构造方法上加上@Lazy注解就可以解决问题。
#Java源码##学习路径#