当前位置: 首页 > 后端技术 > Java

【Spring解析】7.总结二级缓存和三级缓存,面试官,你的回答正确吗?

时间:2023-04-01 20:39:53 Java

盖琴Q:Spring是如何解决循环依赖的?答:支持提前暴露当前正在创建的单例,这个单例可能没有完全初始化。Q:三级缓存有必要吗?答:不需要,可以支持两个缓存,在Spring2.5.3版本中,只使用两个缓存来解决循环依赖。showyouthecode欢迎访问地址:三级缓存不用clone调试。注意:上面的例子实际上依赖的是Spring版本:2.5.3,适用于Java7,所以需要先调整一个属性绕过Spring框架的检查。如果要调试源码,可以点击如下:下载源码和文档,然后断点调试。如果要切换三级缓存实现,可以直接修改pom.xml文件中的Spring版本,直接升级版本到2.5.4,然后重启MavenReloadandDownloadSourceandDocument即可。结论性循环依赖,表现形式很简单,即A->B(A引用B),B->A(B引用A),在其他技术应用场景中可能会出现常见的死锁问题。在讨论Spring如何解决循环依赖之前,需要先了解两个概念:1.普通对象和代理对象普通对象:是指普通对象,由带参数或不带参数的构造函数newInstance实例化,由Spring赋值并执行的对象其他初始化操作后得到的接近普通new操作得到的对象;代理对象:是Spring通过代理技术生成的对象,比如内置的Jdk动态代理、CGLIB代理,在原有实例的基础上增加了额外的行为。怎么了?从类层面看,代理对象类型总是低于或等于(子类化)普通对象类型(或相同的Class类型)。另外,代理对象其实是给普通对象加了一层包装,代理行为在外面,包含了实际的对象(可以这样理解,在Spring中,其实是有两个相同类型的对象,而代理对象内部指的是普通对象)。Spring代理对象对循环依赖带来的棘手问题也解决了,即不管最终依赖是普通对象还是代理对象,属性的类型足以支持引用赋值(可以是指定为公共对象引用或代理对象引用)。2.Spring的Bean创建过程Spring的Bean创建分为三个阶段:实例化:简单理解就是Spring擅自使用newInstance操作为我们调用无参构造函数来创建一个普通的对象。这时,普通对象的所有者引用但未赋值的内部属性的属性填充:拥有对象后,需要给对象中的属性赋值,比如常见的@Autowired和@Value等,而注入的依赖对象可能会导致循环引用初始化:填充内部属性后,as对象执行一系列其他操作。这时候可能会在原有对象的基础上,再加上一层外壳(额外行为),就是代理对象(也就是正常的代理对象生成阶段),最后才是对象构造过程完成。说:在实例化和属性填充阶段,对象是不完整的,而在初始化阶段之后,无论是否生成代理对象,这个阶段之后的Bean都是最终形态。3、最后明白以上两点后,继续往下走。打破僵局的方式有很多种,Spring的解决方案主要是支持当前正在创建的单例提前暴露,可以不完全构造。有人可能会疑惑,如果B对象提前加载了A的代理对象,即B引用了代理对象A'并完成了B对象自身的构建,而A的普通对象目前处于填充属性,可能还有其他属性需要在填充B引用后进行。它们是如何关联的?这就把我们带回到刚才的第一点,即:代理对象其实是对一个普通对象的封装,其他的属性填充、初始化等操作最终都会对原始对象进行。因此,原始对象只有一个,final属性所依赖的对象,是代理对象A'还是普通对象A,只取决于是否被套壳。就算是,因为代理技术的支持,可以将代理对象A'赋值给属性A。加铆钉在Spring2.5.3的源码中,开发者只用了两次缓存来解决循环依赖,看下在源码处,可以看到:在注释中,明确允许提前引用当前正在创建的单例对象,用于解决循环依赖。然后,查看Spring2.5.4的源码、代码注释和changelog,都找不到关于新的三级缓存的描述。在我看来,新的缓存只是为了让作者清理代码流,加快Spring的速度。至于新增的属性,如果是bug,至少在changelog中会提到,但其实不值一提。回到文章开头的问题:Q:Spring是如何解决循环依赖的?答:支持提前暴露当前正在创建的单例,这个单例可能没有完全初始化。Spring2.5.3使用二级缓存,Spring2.5.4及以后使用三级缓存。其实要解决循环依赖,甚至只需要一级缓存,二级缓存就没有必要了。你能接受这个答案吗?EndDefaultSingletonBeanRegistry:给我的只是一小部分属性,给我的是Java千篇一律世界的狂欢。三级缓存博文什么时候开始还不确定,但是可以肯定的是它会充斥网络。希望每一位纠结于三级缓存的面试官,或者即将成为面试官的Javaer,都能读一读这篇文章,否则,在这里有所收获的读者,恐怕只会增加风险面试被骂^_^|。由于Spring已经迁移到github,仓库源码版本最早为:3.0.0。这里附上spring2.5.3和spring2.5.4的完整源码文件和changelog(密码:othl)的下载链接,感兴趣的可以自行获取。