Spring知识点(一)

您所在的位置:网站首页 spring解决了什么问题 Spring知识点(一)

Spring知识点(一)

2023-03-16 07:24| 来源: 网络整理| 查看: 265

Spring循环依赖的问题,对于深入理解spring框架有着重要意义,毕竟spring容器核心功能之一就是依赖注入。

Spring 中设计了三级缓存来解决循环依赖问题,当我们去调用 getBean()方法的时候,Spring 会先从一级缓存中去找到目标 Bean,如果发现一级缓存中没有便会去二级缓存中去找,而如果一、二级缓存中都没有找到,意味着该目标 Bean 还没有实例化。于是,Spring 容器会实例化目标 Bean(PS:刚初始化的 Bean称为早期 Bean)。然后,将目标 Bean 放入到二级缓存中,同时,加上标记是否存在循环依赖。如果不存在循环依赖便会将目标 Bean 存入到二级缓存,否则,便会标记该 Bean 存在循环依赖,然后将等待下一次轮询赋值,也就是解析 @Autowired 注解。等@Autowired 注解赋值完成后,会将目标 Bean 存入到一级缓存。

Spring 一级缓存中存放所有的成熟 Bean,二级缓存中存放所有的早期 Bean,三级缓存中存放代理的bean,先取一级缓存,再取二级缓存。

三级缓存对应的Spring源码,存放在DefaultSingletonBeanRegistry中,有三个map代表三级缓存,

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { /** *一级缓存:单例池 *存放已经初始化的bean——成品 */ private final Map singletonObjects = new ConcurrentHashMap(256); /** *三级缓存:单例工厂的高速缓存 *存放生成bean的工厂 */ private final Map fieldClass = field.getType(); String fieldBeanName = fieldClass.getSimpleName().toLowerCase(); field.set(object, cacheMap.containsKey(fieldBeanName)? cacheMap.get(fieldBeanName) : getBean(fieldClass)); } return (T) object; } ========================= 打印结果为 true true

那么,成熟bean和早期bean有什么区别呢?

——其实就是实例化和初始化的关系,前者相当于直接用 class.newInstance()来实例化一个类,这个时候,所有的属性,都为空,只有把所有的属性都塞了值,才算是初始化完成。

为什么要用三级缓存,一级或者二级不行吗?

按照上图的代码,一级缓存是可以解决一些简单的循环依赖问题的,但是在Spring中,会变得特别麻烦,要做太多的处理,容易出现 npe的问题。

二级缓存,一个放早期bean 一个放成熟bean,可以解决问题,但是考虑到spring aop的特性,不能一开始就创建所有的类,这样会消耗性能和内容,所以在增强的时候,进行创建,需要用到工厂的缓存

传送门:Spring 是如何解决循环依赖的?



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3