分别用一二三级缓存解决循环依赖的方案
Posted 技术无产者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分别用一二三级缓存解决循环依赖的方案相关的知识,希望对你有一定的参考价值。
一. 一级缓存
1.不考虑aop 使用—级缓存解决循环依赖
1>创建A对象,放到缓存中,这时候为A对象注入属性
2>创建B放到缓存,从缓存中获得A对象,将B对象返回给A对象(这时候如果不考虑aop 一级缓存就可以解决循环依赖的问题了)
2.考虑aop时,一级缓存无法解决循环依赖的问题
因为初始化操作必须放在aop代理之前, 否则导致初始化的时候无法改变代理对象的属性值( 具体见动态代理对象属性注入的文章 动态代理对象的属性注入_zyz的博客-CSDN博客),假设A和B对象互相引用,且A和B对象都使用aop进行了增强,则按照上面的逻辑,A对象放到缓存后,需要注入B对象,而缓存中没有B对象,则需要去创建B对象,这时候B对象可以从缓存中获得A对象,而B对象拿到的是没有进行aop增强的A对象,这时候就算把初始化B对象和为B对象生成aop代理的业务逻辑放在这,也只能保证A对象获得的是aop代理过的B对象,而B对象中的A对象是没有经过aop增强的,且经过jdk/cglib动态代理后对象的属性值是没有办法改变的,这时候为A生成aop增强过的对象也无法替换B对象中的A对象,所以一级缓存无法解决。
二.二级缓存
二级缓存可以解决循环依赖,并且也可以解决循环依赖中的依赖对象被aop代理问题,只需要在三级循环的代码中
就是普通对象初始化完成后,然后走到 getSingleton方法通过三级缓存创建对象, 假设A和B循环依赖,并且A和B都通过aop增强,假设先创建A,则当为A中注入B时,发现 B没有,就会去创建B,如果使用二级缓存,这时候直接通过对象工厂创建A的aop对象 ,放在一级缓存中,相当于A对象创建好了,这时候创建好B对象后,返回继续创建A对 象,这时候按顺序,A的属性注入后该进行初始化A对象了,但这时候在创建B时已经把 A对象放到一级缓存中了,这时候如果另一个线程来获取就会获得还没有完全初始化的 A对象(框架是单线程加载的,当框架加载好所有对象都创建好了,因该不会出现不安 全发布的情况),这时候也就会出现违背Spring创建对象的原则,即在对象没有完全初 始化的时候就出现在了一级缓存中,Spring创建对象的原则是在对象被完全初始化后才能被放到缓存中,被外界获取。 三.三级缓存 A 假设和 B 相互引用,且都被 aop 增强 1.A 对象先封装一个回调函数到三级循 环中,这个接口里封装的是 aop 使用 bean 来创建 aop 代理类的方法 2. 这时候 如果为 A 对象中有 B 类的属性,需要把 B 注入到 A 中 3. 这时候没有创建 B 类的 对象,就去创建,也是封装一个回调函数到三级缓存中 4. 这时候需要往 B 中注入 A ,发现 A 在三级循环中,这时候会调用回调函数的 getObject 方法 获得 aop 增强过的 A 对象,放入二级缓存中,因为 A 对象没有初始化完成, 这个对象是不完整的,其实也可直接放使用二级缓存来解决循环依赖 5. 但 是用二级缓存的话会破坏 spring 创建对象的原则,一级缓存存放的是已经 初始化过的完整的对象,二级三级都是半成品,, Spring 更 喜欢把所有的普通 Bean 都初始化完成,在处理代理对象的初始化。以上是关于分别用一二三级缓存解决循环依赖的方案的主要内容,如果未能解决你的问题,请参考以下文章