-
2022-02-16 14:36:31
Spring三级缓存
是为了解决对象间的循环依赖问题。A依赖B,B依赖A,这就是一个简单的循环依赖。
我们来先看看三级缓存的源码。
(1)查看“获取Bean”的源码,注意getSingleton()方法。
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { //第1级缓存 用于存放 已经属性赋值、完成初始化的 单列BEAN private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //第2级缓存 用于存在已经实例化,还未做代理属性赋值操作的 单例BEAN private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); //第3级缓存 存储创建单例BEAN的工厂 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); //已经注册的单例池里的beanName private final Set<String> registeredSingletons = new LinkedHashSet<>(256); //正在创建中的beanName集合 private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); //缓存查找bean 如果第1级缓存没有,那么从第2级缓存获取。如果第2级缓存也没有,那么从第3级缓存创建,并放入第2级缓存。 protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); //第1级 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); //第2级 if (singletonObject == null && allowEarlyReference) { //第3级缓存 在doCreateBean中创建了bean的实例后,封装ObjectFactory放入缓存的bean实例 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { //创建未赋值的bean singletonObject = singletonFactory.getObject(); //放入到第2级缓存 this.earlySingletonObjects.put(beanName, singletonObject); //从第3级缓存删除 this.singletonFactories.remove(beanName); } } } } return singletonObject; } }
(2)“添加到第1级缓存”的源码:
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { // 放入第1级缓存 this.singletonObjects.put(beanName, singletonObject); // 从第3级缓存删除 this.singletonFactories.remove(beanName); // 从第2级缓存删除 this.earlySingletonObjects.remove(beanName); // 放入已注册的单例池里 this.registeredSingletons.add(beanName); } }
(3)“添加到第3级缓存”的源码:
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { synchronized (this.singletonObjects) { // 若第1级缓存没有bean实例 if (!this.singletonObjects.containsKey(beanName)) { // 放入第3级缓存 this.singletonFactories.put(beanName, singletonFactory); // 从第2级缓存删除,确保第2级缓存没有该bean this.earlySingletonObjects.remove(beanName); // 放入已注册的单例池里 this.registeredSingletons.add(beanName); } } }
(4)“创建Bean”的源码:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException { BeanWrapper instanceWrapper = null; if (instanceWrapper == null) { //实例化对象 instanceWrapper = this.createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null; Class<?> beanType = instanceWrapper != null ? instanceWrapper.getWrappedClass() : null; //判断是否允许提前暴露对象,如果允许,则直接添加一个 ObjectFactory 到第3级缓存 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { //添加到第3级缓存 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } //填充属性 this.populateBean(beanName, mbd, instanceWrapper); //执行初始化方法,并创建代理 exposedObject = initializeBean(beanName, exposedObject, mbd); return exposedObject; }
通过这段代码,我们可以知道:
Spring
在实例化对象之后,就会为其创建一个Bean
工厂,并将此工厂加入到三级缓存中。因此,Spring 一开始提前暴露的并不是实例化的 Bean,而是将 Bean 包装起来的ObjectFactory。为什么要这么做呢?
这实际上涉及到
AOP
。如果创建的Bean
是有代理的,那么注入的就应该是代理Bean
,而不是原始的Bean
。但是,Spring
一开始并不知道Bean
是否会有循环依赖,通常情况下(没有循环依赖的情况下),Spring
都会在“完成填充属性并且执行完初始化方法”之后再为其创建代理。但是,如果出现了循环依赖,Spring
就不得不为其提前创建"代理对象";否则,注入的就是一个原始对象,而不是代理对象。因此,这里就涉及到"应该在哪里提前创建代理对象"?Spring
的做法就是:在ObjectFactory
中去提前创建代理对象。它会执行getObject()
方法来获取到 Bean。实际上,它真正执行的方法如下:protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; // 如果需要代理,这里会返回代理对象;否则,返回原始对象。 exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } return exposedObject; }
提前进行对象的代理工作,并在
earlyProxyReferences
map中记录已被代理的对象,是为了避免在后面重复创建代理对象。public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { @Override public Object getEarlyBeanReference(Object bean, String beanName) { Object cacheKey = getCacheKey(bean.getClass(), beanName); // 记录已被代理的对象 this.earlyProxyReferences.put(cacheKey, bean); return wrapIfNecessary(bean, beanName, cacheKey); } }
再次分析获取bean的方法getSingleton()方法,可知:
提前暴露的对象,虽然已实例化,但是没有进行属性填充,还没有完成初始化,是一个不完整的对象。 这个对象存放在二级缓存中,对于三级缓存机制十分重要,是解决循环依赖一个非常巧妙的设计。
让我们来分析一下“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情景。
- A 调用
doCreateBean()
创建Bean对象:由于还未创建,从第1级缓存singletonObjects
查不到,此时只是一个半成品(提前暴露的对象),放入第3级缓存singletonFactories
。 - A在属性填充时发现自己需要B对象,但是在三级缓存中均未发现B,于是创建B的半成品,放入第3级缓存
singletonFactories
。 - B在属性填充时发现自己需要A对象,从第1级缓存
singletonObjects
和第2级缓存earlySingletonObjects
中未发现A,但是在第3级缓存singletonFactories
中发现A,将A放入第2级缓存earlySingletonObjects
,同时从第3级缓存singletonFactories
删除。 - 将A注入到对象B中。
- B完成属性填充,执行初始化方法,将自己放入第1级缓存
singletonObjects
中(此时B是一个完整的对象),同时从第3级缓存singletonFactories和
第2级缓存earlySingletonObjects
中删除
。 - A得到“对象B的完整实例”,将B注入到A中。
- A完成属性填充,执行初始化方法,并放入到第1级缓存
singletonObjects
中。
在创建过程中,都是从第三级缓存(对象工厂创建不完整对象),将提前暴露的对象放入到第二级缓存;从第二级缓存拿到后,完成初始化,并放入第一级缓存。
更多相关内容 - A 调用
-
浅谈Android 中图片的三级缓存策略
2021-01-05 10:51:22什么是三级缓存? 内存缓存,优先加载,速度最快 本地缓存,次优先加载,速度快 网络缓存,最后加载,速度慢,浪费流量 为什么要进行三级缓存 三级缓存策略,最实在的意义就是 减少不必要的流量消耗,增加加载... -
Android三级缓存原理讲解
2021-01-06 01:51:50三级缓存 内存缓存 本地缓存(SD卡缓存) 网络缓存 缓存顺序:首先从网络获取图片资源,然后将当前的图片缓存到本地,然后再缓存到内存中,那么下次访问图片资源就会优先从内存获取图片资源,如果内存中没有那么... -
详解Android中图片的三级缓存及实例
2021-01-06 01:14:59详解Android中图片的三级缓存及实例 为什么要使用三级缓存 如今的 Android App 经常会需要网络交互,通过网络获取图片是再正常不过的事了 假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量。在当前的... -
图片三级缓存
2018-09-19 10:49:57图片的三级缓存Util 内存 磁盘 网络缓存(HttpURLConnection) -
Spring的三级缓存
2022-06-12 13:42:29主要参考以下几篇文章做了简单的总结:一文告诉你Spring是如何利用"三级缓存"巧妙解决Bean的循环依赖问题的Spring循环依赖三级缓存是否可以去掉第三级缓存spring:我是如何解决循环依赖的?Spring 解决循环依赖为什么...Spring三级缓存
对象创建的过程
- spring的三级缓存分别是
// 从上至下 分表代表这“三级缓存” private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //一级缓存 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二级缓存 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存
singletonObjects
:用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用earlySingletonObjects
:提前曝光的单例对象的cache,存放原始的 bean 对象(尚未填充属性),用于解决循环依赖singletonFactories
:单例对象工厂的cache,存放 bean 工厂对象,用于解决循环依赖
- 对象创建流程
-
AbstractBeanFactory
中的doGetBean()
方法 -
DefaultSingletonBeanRegistry
中的getSingleton()
方法protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory=this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
- 先从一级缓存singletonObjects中去获取。(如果获取到就直接return)
- 如果获取不到或者对象正在创建中(isSingletonCurrentlyInCreation()),那就再从二级缓存earlySingletonObjects中获取。(如果获取到就直接return)
- 如果还是获取不到,且允许singletonFactories(allowEarlyReference=true)通过getObject()获取。就从三级缓存singletonFactory.getObject()获取。(如果获取到了就从singletonFactories中移除,并且放进earlySingletonObjects。其实也就是从三级缓存移动(是剪切、不是复制哦~)到了二级缓存)此处的移动保证了,之后在init时候仍然是同一个对象
-
AbstractAutowireCapableBeanFactory.createBean/doCreateBean()
-
实例化
// 使用构造器/工厂方法 instanceWrapper是一个BeanWrapper
instanceWrapper = createBeanInstance(beanName, mbd, args);
// 此处bean为"原始Bean" 也就是这里的A实例对象:A@1234
final Object bean = instanceWrapper.getWrappedInstance(); -
添加到三级缓存
// 允许暴露,就把A绑定在ObjectFactory上,注册到三级缓存
singletonFactories
里面去保存着
// Tips:这里后置处理器的getEarlyBeanReference方法会被促发,自动代理创建器在此处创建代理对象(注意执行时机 为执行三级缓存的时候)
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
//注意 此时加入的是一个factory没有执行
-
-
属性赋值
//此时候上面说到的getEarlyBeanReference方法就会被执行。这也解释为何我们@Autowired是个代理对象,而不是普通对象的根本原因
populateBean(beanName, mbd, instanceWrapper);
-
解决循环依赖,在获取单例对象时
singletonFactory.getObject()调用了
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16); @Override public Object getEarlyBeanReference(Object bean, String beanName) { Object cacheKey = getCacheKey(bean.getClass(), beanName); this.earlyProxyReferences.put(cacheKey, bean); /* 这里,主要就是看看到底要不要生成代理对象,要的话,就生成,不要就算了,另外,做了个标记:在earlyProxyReferences加了当前bean的key,表示:当前bean,已经被getEarlyBeanReference方法处理过了。 /至于,最终到底有没有生成代理对象,另说。毕竟调用wrapIfNecessary也不是说,一定就满足切面,要生成代理对象。 可能返回的仍然是原始对象。*/ return wrapIfNecessary(bean, beanName, cacheKey); } }
此处的SmartInstantiationAwareBeanPostProcessor继承自BeanPostProcessor
BeanPostProcessor接口会在init阶段生成对对象的代理,
getCacheKey
保证不会重复生成代理对象-
初始化对象
如果有代理会检查是否发生了循环依赖
exposedObject = initializeBean(beanName, exposedObject, mbd); ... // 至此,相当于A@1234已经实例化完成、初始化完成(属性也全部赋值了~) // 这一步我把它理解为校验:校验:校验是否有循环引用问题~~~~~ if (earlySingletonExposure) { // 注意此处第二个参数传的false,表示不去三级缓存里singletonFactories再去调用一次getObject()方法了~~~ // 上面建讲到了由于B在初始化的时候,会触发A的ObjectFactory.getObject() 所以a此处已经在二级缓存earlySingletonObjects里了 // 因此此处返回A的实例:A@1234 Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { // 这个等式表示,exposedObject若没有再被代理过,这里就是相等的 // 显然此处我们的a对象的exposedObject它是没有被代理过的 所以if会进去~ // 这种情况至此,就全部结束了~~~ if (exposedObject == bean) { exposedObject = earlySingletonReference; } // 继续以A为例,比如方法标注了@Aysnc注解,exposedObject此时候就是一个代理对象,因此就会进到这里来 //hasDependentBean(beanName)是肯定为true,因为getDependentBeans(beanName)得到的是["b"]这个依赖 else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); // A@1234依赖的是["b"],所以此处去检查b // 如果最终存在实际依赖的bean:actualDependentBeans不为空 那就抛出异常 证明循环引用了~ for (String dependentBean : dependentBeans) { // 这个判断原则是:如果此时候b并还没有创建好,this.alreadyCreated.contains(beanName)=true表示此bean已经被创建过,就返回false // 若该bean没有在alreadyCreated缓存里,就是说没被创建过(其实只有CreatedForTypeCheckOnly才会是此仓库) if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } }
-
是否可以没有二级缓存
如果只在两个对象AB产生循环依赖时,可以不需要。
但是如果是ABC产生循环依赖时
@Service public class TestService1 { @Autowired private TestService2 testService2; @Autowired private TestService3 testService3; public void test1() { } } @Service public class TestService2 { @Autowired private TestService1 testService1; public void test2() { } } @Service public class TestService3 { @Autowired private TestService1 testService1; public void test3() { } }
TestService1注入到TestService3又需要从第三级缓存中获取实例,而第三级缓存里保存的并非真正的实例对象,而是
ObjectFactory
对象。说白了,两次从三级缓存中获取都是ObjectFactory
对象,而通过它创建的实例对象每次可能都不一样的。这样不是有问题?
为了解决这个问题,spring引入的第二级缓存。上面图1其实TestService1对象的实例已经被添加到第二级缓存中了,而在TestService1注入到TestService3时,只用从第二级缓存中获取该对象即可。
是否需要三级缓存
如果创建的
Bean
有对应的代理
,那其他对象注入时,注入的应该是对应的代理对象
;但是Spring
无法提前知道这个对象是不是有循环依赖
的情况,而正常情况
下(没有循环依赖
情况),Spring
都是在创建好完成品Bean
之后才创建对应的代理
。这时候Spring
有两个选择:- 不管有没有循环依赖,都提前创建好代理对象,并将代理对象放入缓存,出现循环依赖时,其他对象直接就可以取到代理对象并注入。
- 不提前创建好代理对象,在出现循环依赖被其他对象注入时,才实时生成代理对象。这样在没有循环依赖`的情况下,Bean就可以按着Spring设计原则的步骤来创建。
Spring
选择了第二种方式,那怎么做到提前曝光对象而又不生成代理呢?
Spring就是在对象外面包一层ObjectFactory
,提前曝光的是ObjectFactory
对象,在被注入时才在ObjectFactory.getObject
方式内实时生成代理对象,并将生成好的代理对象放入到第二级缓存Map<String, Object> earlySingletonObjects
。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
主要参考以下几篇文章做了简单的总结:
-
安卓三级缓存
2016-12-28 16:20:07三级缓存 -
Spring三级缓存以及面试题
2022-01-22 16:28:42Spring的三级缓存 三级缓存的作用:解决循环依赖的问题 循环依赖问题:说白是一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了构成一个环形调用 代码描述: @Service public class ...Spring的三级缓存
三级缓存的作用:解决循环依赖的问题
循环依赖问题:说白是一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了构成一个环形调用
代码描述:
@Service public class AServiceImpl implements AService { @Autowired private BService bService; ... } @Service public class BServiceImpl implements BService { @Autowired private AService aService; ... }
什么是三级缓存?
- singletonObjects(一级,日常实际获取Bean的地方,里面保存的都是初始化后的Bean);
- earlySingletonObjects(二级,还没进行属性注入,由三级缓存放进来,经过三级缓存处理可能是原对象或代理对象);
- singletonFactories(三级,存放一个对象工厂,和lambda表达式,里面保存的都是刚实例化的对象);
本质上这三级缓存就是三个Map :
/** 1级缓存 Cache of singleton objects: bean name to bean instance. */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** 2级缓存 Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); /** 3级缓存 Cache of singleton factories: bean name to ObjectFactory. */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
我们知道了什么是循环依赖,什么是三级缓存,那么我们的Spring是如何通过三级缓存去解决这个问题的呢?
如下图流程:
首先先知道两个概念:
- 实例化:我们只是将对象创建出来,并没有进行赋值操作
- 初始化:对我们创建出来的对象也就是实例对象进行属性注入后的对象
接下来我们对这个图进行解释说明:
1、我们创建Aservice对象,将其对应的lambda表达式放入三级缓存,lambda表达式的作用是,判断我们这个实例化对象是否有AOP曹操作,如果有就执行AOP,返回代理后的对象到二级缓存,如果没有,则直接将原对象放入二级缓存 ;
2、然后我们的对Aservice这个实例化对象进行属性注入,填充Bservice对象,首先是去一级缓存中去找,如果没有就去创建Bservice对象
3、初始步骤同样是将Bservice对应的lambda表达式放入我们的三级缓存当中,发现B同样需要注入AService属性
4、就会去一级缓存和二级缓存中找Aservice,发现不存在,那么就去三级缓存当中查找,
5、找到了,那么此时执行三级缓存中Aservice对应的lambda表达式,同步骤1一样,将返回的对象放入二级缓存当中
6、此时,我们的Bservice中有了Aservice但是,Aservice中的Bservice属性尚未注入,对其进行属性注入
7、执行三级缓存中Bservice对应的lambda表达式,得到Bservice对象,并将Bservice对象由二级缓存移入到一级缓存
8、此时Bservice结束
9、继续对Aservice进行属性注入,将一级缓存中的Bservice填充到Aservice,接下来就是初始化Aservice
10、Aservice初始化完毕,将Aservice移入到一级缓存
11、此时Aservice结束
12、循环依赖注入的问题就这样解决了!
Spring相关面试题
如下是Spring的高频面试题,需要掌握!
1、说一下Spring中IOC的构建流程(初始化过程) ?
1、通过BeanFactory 或者 ApplicationContex接口,以及其实现类,读取我们的beans.xml,创建IOC容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
ClassPathXmlApplicationContext
创建容器对象时,构造方法做了如下两件事:- ① 调用父容器的构造方法为容器先设置好 Bean 资源加载器。
- ② 调用父类的 setConfigLocations() 方法设置 Bean 配置信息的定位路径。
- ③ 调用父类 AbstractApplicationContext 的 refresh() 方法启动整个 IOC 容器对 Bean 的载入,在创建 IOC 容器前如果已有容器存在,需要把已有的容器销毁,保证在 refresh() 方法后使用的是新创建的 IOC 容器。
2、容器创建完成后,通过
loadBeanDefinitions()
方法加载 Bean 配置资源,该方法在加载资源时,首先解析配置文件路径,读取配置文件的内容,然后通过 XML 解析器将 Bean 的配置信息转换成文档对象,之后按照 Spring Bean 的定义规则将文档对象解析为 BeanDefinition 对象。3、然后将beanName做为Key,BeanDefiniton对象作为Value保存在我们的BeanDefinitonMap中,然后遍历Map集合
4、最后,实例化所有的 Bean 实例(非懒加载):包括实例的创建,实例的属性填充,实例的初始化。
2、说一下Bean加载
参考文章:https://blog.csdn.net/weixin_43591980/article/details/117022413
3、说一下SpringBean的生命周期
简述:从实例创建到对象销毁
- Bean 的实例化阶段:创建一个 Bean 对象。
- Bean 实例的属性填充阶段:为 Bean 实例的属性赋值。
- Bean 实例的初始化阶段:对 Bean 实例进行初始化。
- Bean 实例的正常使用阶段。
- Bean 实例的销毁阶段:容器关闭后,将 Bean 实例销毁。
详细流程:
当我们IOC容器创建完成之后,会读取我们bean.xml中的bean标签,然后将其封装成一个BeanDefiniton对象,然后将beanName做为Key,BeanDefiniton对象作为Value保存在我们的BeanDefinitonMap中,然后遍历我们的Map集合,此时对每Bean进行实例化,接着就是对Bean进行属性注入,此时在我们要调用Bean的init方法的时候,会在执行之前调用后置处理器的一个befor方法:postProcessBeforeInitialization(),接下来就是执行Init方法,完成Bean的初始化操作,接着会再次调用后置处理器的一个after方法 :postProcessAfterInitialization(),当after方法执行完毕后,我们就得到了一个可用的Bean对象在IOC容器当中,当我们容器关闭的时候,就会调用我们Bean的Destory方法,将我们的Bean进行销毁处理!
4、什么是Spring的循环依赖问题?
循环依赖:说白是一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了构成一个环形调用,如图:
@Service public class AServiceImpl implements AService { @Autowired private BService bService; ... } @Service public class BServiceImpl implements BService { @Autowired private AService aService; ... }
注意:目前Spring只支持单例(Singleton)类型的属性循环依赖
5、说一下Spring的三级缓存
所谓的三级缓存其实就是三个Map…首先明确一定,我对这里的三级缓存定义是这样的:
- singletonObjects(一级,日常实际获取Bean的地方);
- earlySingletonObjects(二级,还没进行属性注入,由三级缓存放进来);
- singletonFactories(三级,Value是一个对象工厂);
6、Spring是如何解决循环依赖的?
参考文章:https://www.cnblogs.com/semi-sub/p/13548479.html
答:Spring通过三级缓存解决循环依赖问题!
我们通过A实例依赖B,B实例依赖A的例子来分析具体流程:
1、A对象实例化之后,属性注入之前,其实会把A对象放入三级缓存中,key是BeanName,Value是ObjectFactory
2、等到A对象属性注入时,发现依赖B,又去实例化B时
3、B属性注入需要去获取A对象,这里就是从三级缓存里拿出ObjectFactory,ObjectFactory得到对应的Bean(就是对象A)
4、把三级缓存的A记录给干掉,然后放到二级缓存中
5、显然,二级缓存存储的key是BeanName,value就是Bean(这里的Bean还没做完属性注入相关的工作)
6、等到完全初始化之后,就会把二级缓存给remove掉,塞到一级缓存中
7、我们自己去getBean的时候,实际上拿到的是一级缓存的
大致的过程就是这样
7、Spring为什么是三级缓存?
参考文章:https://www.cnblogs.com/grey-wolf/p/13034371.html
三级缓存的职能:https://blog.csdn.net/m0_43448868/article/details/113578628
如果没有AOP的话确实可以两级缓存就可以解决循环依赖的问题,如果加上AOP,两级缓存是无法解决的,不可能每次执行singleFactory.getObject()方法都给我产生一个新的代理对象,所以还要借助另外一个缓存来保存产生的代理对象
8、BeanFactory 和 FactoryBean 的区别
- BeanFactory:Spring 容器最核心也是最基础的接口,本质是个工厂类,用于管理 bean 的工厂,最核心的功能是加载 bean
- FactoryBean:该接口以 bean 样式定义,但是它不是一种普通的 bean,它是个工厂 bean,实现该接口的类可以自己定义要创建的 bean,只需要实现它的 getObject 方法即可
9、BeanFactory 和 ApplicationContext 的区别
Spring提供的2个创建IOC容器的接口,之间的的区别如下:
1、BeanFactory : IOC容器的基本实现,是Spring内部使用的接口,不提供给开发人员使用 ;
- 加载配置文件的时候,不会创建对象,而是当我们的使用的时候才回去创建对象!
2、ApplicationContext : BeanFactory的子接口提供更多更强大的功能,一般由开发人员进行使用 ; 【推荐】
- 加载配置文件的时候,会把配置文件中的对象进行创建!
10、说一下SpinrgBean的作用范围?
通过 scope 属性指定 Bean 的作用范围,包括:
- singleton:单例模式,表示Spring的IOC容器当中只能存在一个Bean实例,默认的。
- prototype:多实例模式,表示每次从IOC容器当中取一个Bean实例的时候,都是一个新的Bean 。
- request:每次创建对象,都放在我们的Request域当中(很少用)在一次请求范围内,创建一个实例。
- session:每次创建对象,都放在我们的session域当中(很少用)在一个会话范围内,创建一个实例。
- globle-session:在servletContext范围内,创建一个实例
后面三个范围需要在web环境才起作用
关于singleton和prototype还存在一个区别就是:
当我们的
scop=singleton
的时候我们的对象是会在ApplicaitionContex加载xml文件的时候创建的;当我们的
scop=prototype
的时候我们的对象不是在加载xml的时候创建的,而是在调用getBean方法的时候创建的!11、多个AOP的顺序怎么定
我们通过**@Order注解来设置增强类优先级:这个值越小优先级越高**!
@Order(3) public class UserProxy {} @Order(1) public class PersonProxy {}
12、Spring 的 AOP 有哪几种创建代理的方式
Spring 中的 AOP 目前支持 JDK 动态代理和 Cglib 代理。
通常来说:如果被代理对象实现了接口,则使用 JDK 动态代理,否则使用 Cglib 代理。另外,也可以通过指定 proxyTargetClass=true 来
实现强制走 Cglib 代理。
13、JDK 动态代理和 Cglib 代理的区别
- JDK 动态代理主要是针对类实现了某个接口,AOP 则会使用 JDK 动态代理。他基于反射的机制实现,生成一个实现同样接口的一个代理类,然后通过重写方法的方式,实现对代码的增强。
- 而如果某个类没有实现接口,AOP 则会使用 CGLIB 代理。他的底层原理是基于 ASM 第三方框架,通过修改字节码生成一个子类,然后重写父类的方法,实现对代码的增强。
14、JDK 动态代理为什么只能对实现了接口的类生成代理
根本原因是通过 JDK 动态代理生成的类已经继承了 Proxy 类,所以无法再使用继承的方式去对类实现代理
15、Spring 事务的实现原理
Spring 事务的底层实现主要使用的技术:AOP(动态代理) + ThreadLocal + try/catch。
动态代理:基本所有要进行逻辑增强的地方都会用到动态代理,AOP 底层也是通过动态代理实现。
ThreadLocal:主要用于线程间的资源隔离,以此实现不同线程可以使用不同的数据源、隔离级别等等。
try/catch:最终是执行 commit 还是 rollback,是根据业务逻辑处理是否抛出异常来决定。
Spring 事务的核心逻辑伪代码如下:
public void invokeWithinTransaction() { // 1.事务资源准备 try { // 2.业务逻辑处理,也就是调用被代理的方法 } catch (Exception e) { // 3.出现异常,进行回滚并将异常抛出 } finally { // 现场还原:还原旧的事务信息 } // 4.正常执行,进行事务的提交 // 返回业务逻辑处理结果 }
16、Spring框架提供哪几种事务传播行为
1、REQUIRED:Spring 默认的事务传播级别,如果上下文中已经存在事务,那么就加入到事务中执行,如果当前上下文中不存在事务,则新建事务执行。
2)REQUIRES_NEW:每次都会新建一个事务,如果上下文中有事务,则将上下文的事务挂起,当新建事务执行完成以后,上下文事务再恢复执行。
3)SUPPORTS:如果上下文存在事务,则加入到事务执行,如果没有事务,则使用非事务的方式执行。
4)MANDATORY:上下文中必须要存在事务,否则就会抛出异常。
5)NOT_SUPPORTED :如果上下文中存在事务,则挂起事务,执行当前逻辑,结束后恢复上下文的事务。
6)NEVER:上下文中不能存在事务,否则就会抛出异常。
7)NESTED:嵌套事务。如果上下文中存在事务,则嵌套事务执行,如果不存在事务,则新建事务。
17、Spring 的事务隔离级别
Spring 的事务隔离级别底层其实是基于数据库的,Spring 并没有自己的一套隔离级别。
-
READ_UNCOMMITTED:读未提交,最低的隔离级别,会读取到其他事务还未提交的内容,存在脏读。
-
READ_COMMITTED:读已提交,读取到的内容都是已经提交的,可以解决脏读,但是存在不可重复读。
-
REPEATABLE_READ:可重复读,在一个事务中多次读取时看到相同的内容,可以解决不可重复读,但是存在幻读。
-
SERIALIZABLE:串行化,最高的隔离级别,对于同一行记录,写会加写锁,读会加读锁。在这种情况下,只有读读能并发执行,其他并行的读写、写读、写写操作都是冲突的,需要串行执行。可以防止脏读、不可重复度、幻读,没有并发事务问题。
18、Spring中用到的设计模式
代理模式、工厂模式、单例模式、观察者模式、适配器模式
19、@Resource 和 @Autowire 的区别
- @Resource是Java的原生注解、@Autowired是我们Spring中的注解
- @Resource默认是按照名字自动装配,@Autowired是按照类型自动装配
20、@Autowire 怎么使用名称来注入
通过搭配@Qualifire指定bean的名称,来完成byName的装配方式
@Component public class Test { @Autowired @Qualifier("userService") private UserService userService; }
21、如何让两个Bean按顺序加载
方式1、使用 @DependsOn、depends-on
方式2、让后加载的类依赖先加载的类
@Component public class A { @Autowire private B b; }
-
Spring三级缓存源码
2022-03-26 12:17:56Spring三级缓存类源码分析文章目录
Spring三级缓存类源码分析
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { // 1级缓存:存放实例化+属性注入+初始化+代理(如果有代理)后的单例bean private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 2级缓存:存放实例化+代理(如果有代理)后的单例bean private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 3级缓存:存放封装了单例bean(实例化的)的对象工厂 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 已经完成注册的单例beanName private final Set<String> registeredSingletons = new LinkedHashSet<>(256); // 正在创建中的beanName private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); // 当前不检查的bean的集合 private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); // 存放异常出现的相关的原因的集合 private Set<Exception> suppressedExceptions; // 标志,目前是否在销毁单例中 private boolean singletonsCurrentlyInDestruction = false; // 存放一次性bean的缓存 private final Map<String, Object> disposableBeans = new LinkedHashMap<>(); // 外部bean与被包含在外部bean的所有内部bean集合包含关系的缓存 private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16); // 指定bean与依赖指定bean的所有bean的依赖关系的缓存 private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64); // 指定bean与创建这个bean所需要依赖的所有bean的依赖关系的缓存 private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64); /** * 注册单例对象到一级缓存(若一级缓存中已存在则抛出异常) */ @Override public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException { Assert.notNull(beanName, "Bean name must not be null"); Assert.notNull(singletonObject, "Singleton object must not be null"); synchronized (this.singletonObjects) { Object oldObject = this.singletonObjects.get(beanName); // 如果一级缓存有,说明已经注册过 if (oldObject != null) { throw new IllegalStateException("Could not register object [" + singletonObject + "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound"); } // 一级缓存没有,开始注册 addSingleton(beanName, singletonObject); } } /** * 添加到一级缓存(并移除二级、三级缓存) */ protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { // 加入单例对象到一级缓存 this.singletonObjects.put(beanName, singletonObject); // 删除三级缓存 this.singletonFactories.remove(beanName); // 删除二级缓存 this.earlySingletonObjects.remove(beanName); // 加入已注册的bean this.registeredSingletons.add(beanName); } } /** * 添加到三级级缓存 */ protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { // 如果一级缓存没有,添加对象工厂到三级缓存 if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } } /** * 获取单例 */ @Override @Nullable public Object getSingleton(String beanName) { // 允许早期依赖 return getSingleton(beanName, true); } /** * 获取单例 * 2.如果二级缓存有直接返回 * 3.如果三级缓存有,通过singletonFactory.getObject()的到未完成的单例对象,并移除三级缓存,返回未完成的单例对象 * @param allowEarlyReference true:允许早期依赖 * @return */ @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 如果一级缓存有,直接返回 Object singletonObject = this.singletonObjects.get(beanName); // 如果一级缓存没有,但正在创建 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 如果二级缓存中有,说明正在加载,则直接返回 singletonObject = this.earlySingletonObjects.get(beanName); // 二级缓存也没有,且允许早期依赖 if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); // 三级缓存有,调用getObject方法创建bean并放入到二级缓存,并删除三级缓存 if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; } /** * 获取单例 */ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { // 一级缓存有,直接返回 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 当前正在销毁bean,不能创建 if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } // 创建前检查,记录正在加载状态 beforeSingletonCreation(beanName); boolean newSingleton = false; // 如果当前没有异常,初始化异常集合 boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 调用getObject方法创建bean singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // 有可能是其他方式创建的bean singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } // 创建后检查,移除加载状态 afterSingletonCreation(beanName); } // 如果是新创建的bean,添加到一级缓存(并移除二级、三级缓存) if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } } /** * 注册过程中发生的异常,加入到异常集合 */ protected void onSuppressedException(Exception ex) { synchronized (this.singletonObjects) { if (this.suppressedExceptions != null) { this.suppressedExceptions.add(ex); } } } /** * 移除单例,这四个缓存同时移除 */ protected void removeSingleton(String beanName) { synchronized (this.singletonObjects) { this.singletonObjects.remove(beanName); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.remove(beanName); } } /** * 单例是否一存在 */ @Override public boolean containsSingleton(String beanName) { return this.singletonObjects.containsKey(beanName); } /** * 已注册的单例名称集合 */ @Override public String[] getSingletonNames() { synchronized (this.singletonObjects) { return StringUtils.toStringArray(this.registeredSingletons); } } /** * 已注册的单例名称数量 */ @Override public int getSingletonCount() { synchronized (this.singletonObjects) { return this.registeredSingletons.size(); } } /** * 设置不检查的beanName */ public void setCurrentlyInCreation(String beanName, boolean inCreation) { Assert.notNull(beanName, "Bean name must not be null"); if (!inCreation) { this.inCreationCheckExclusions.add(beanName); } else { this.inCreationCheckExclusions.remove(beanName); } } public boolean isCurrentlyInCreation(String beanName) { Assert.notNull(beanName, "Bean name must not be null"); return (!this.inCreationCheckExclusions.contains(beanName) && isActuallyInCreation(beanName)); } protected boolean isActuallyInCreation(String beanName) { return isSingletonCurrentlyInCreation(beanName); } /** * 是否当前创建的bean */ public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); } /** * 创建前检查,记录正在加载状态 */ protected void beforeSingletonCreation(String beanName) { // 如果这个beanName要检查,记录创建状态。如果返回false,说明已经正在创建了,抛异常 if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } } /** * 创建后检查,移除加载状态 */ protected void afterSingletonCreation(String beanName) { // 如果这个beanName要检查,移除创建状态。如果返回false,说明已经创建完了。抛异常 if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } } /** * 注册一次性bean实例 */ public void registerDisposableBean(String beanName, DisposableBean bean) { synchronized (this.disposableBeans) { this.disposableBeans.put(beanName, bean); } } /** * 注册包含的bean */ public void registerContainedBean(String containedBeanName, String containingBeanName) { synchronized (this.containedBeanMap) { // 如果没有key为containingBeanName的value,说明内部bean集合为空,则初始化一个 Set<String> containedBeans = this.containedBeanMap.computeIfAbsent(containingBeanName, k -> new LinkedHashSet<>(8)); // 如果已经存在了对应关系,则直接返回 if (!containedBeans.add(containedBeanName)) { return; } } // 不存在了对应关系,添加对应关系 registerDependentBean(containedBeanName, containingBeanName); } /** * 注册依赖的bean */ public void registerDependentBean(String beanName, String dependentBeanName) { String canonicalName = canonicalName(beanName); synchronized (this.dependentBeanMap) { Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); // 如果已经存在了对应关系,则直接返回 if (!dependentBeans.add(dependentBeanName)) { return; } } // 不经存在了对应关系,添加对应关系 synchronized (this.dependenciesForBeanMap) { Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } } /** * dependentBeanName是否依赖beanName */ protected boolean isDependent(String beanName, String dependentBeanName) { synchronized (this.dependentBeanMap) { return isDependent(beanName, dependentBeanName, null); } } /** * dependentBeanName是否依赖beanName */ private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) { if (alreadySeen != null && alreadySeen.contains(beanName)) { return false; } String canonicalName = canonicalName(beanName); Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName); // bean依赖beanName,直接返回false if (dependentBeans == null) { return false; } // 有其他bean依赖beanName,且包含了dependentBeanName,返回true if (dependentBeans.contains(dependentBeanName)) { return true; } // 有其他bean依赖beanName,但是不包含dependentBeanName for (String transitiveDependency : dependentBeans) { if (alreadySeen == null) { alreadySeen = new HashSet<>(); } alreadySeen.add(beanName); // 是否有循环依赖 if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) { return true; } } return false; } /** * 是否有其他对象依赖指定bean */ protected boolean hasDependentBean(String beanName) { return this.dependentBeanMap.containsKey(beanName); } /** * 返回依赖指定bean的数组 */ public String[] getDependentBeans(String beanName) { Set<String> dependentBeans = this.dependentBeanMap.get(beanName); if (dependentBeans == null) { return new String[0]; } synchronized (this.dependentBeanMap) { return StringUtils.toStringArray(dependentBeans); } } /** * 返回指定bean,依赖其他bean的数组 */ public String[] getDependenciesForBean(String beanName) { Set<String> dependenciesForBean = this.dependenciesForBeanMap.get(beanName); if (dependenciesForBean == null) { return new String[0]; } synchronized (this.dependenciesForBeanMap) { return StringUtils.toStringArray(dependenciesForBean); } } /** * 销毁所有单例 */ public void destroySingletons() { if (logger.isTraceEnabled()) { logger.trace("Destroying singletons in " + this); } // 设置当前正在销毁 synchronized (this.singletonObjects) { this.singletonsCurrentlyInDestruction = true; } String[] disposableBeanNames; synchronized (this.disposableBeans) { disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet()); } // 销毁disposableBeans中的所有bean for (int i = disposableBeanNames.length - 1; i >= 0; i--) { destroySingleton(disposableBeanNames[i]); } // 清空containedBeanMap、dependentBeanMap、dependenciesForBeanMap this.containedBeanMap.clear(); this.dependentBeanMap.clear(); this.dependenciesForBeanMap.clear(); // 清除所有单例缓存 clearSingletonCache(); } /** * 清除所有单例缓存 */ protected void clearSingletonCache() { synchronized (this.singletonObjects) { // 清除所有单例缓存 this.singletonObjects.clear(); this.singletonFactories.clear(); this.earlySingletonObjects.clear(); this.registeredSingletons.clear(); // 清除完后,标志恢复为false this.singletonsCurrentlyInDestruction = false; } } /** * 销毁单例bean */ public void destroySingleton(String beanName) { // 从缓存中移除 removeSingleton(beanName); // 从disposableBeans移除,如果有beanName对应的对象,返回这个对象 DisposableBean disposableBean; synchronized (this.disposableBeans) { disposableBean = (DisposableBean) this.disposableBeans.remove(beanName); } // 销毁bean destroyBean(beanName, disposableBean); } /** * 销毁bean */ protected void destroyBean(String beanName, @Nullable DisposableBean bean) { // 获取依赖当前beanName的bean Set<String> dependencies; synchronized (this.dependentBeanMap) { dependencies = this.dependentBeanMap.remove(beanName); } // 移除依赖当前beanName的bean if (dependencies != null) { if (logger.isTraceEnabled()) { logger.trace("Retrieved dependent beans for bean '" + beanName + "': " + dependencies); } for (String dependentBeanName : dependencies) { destroySingleton(dependentBeanName); } } if (bean != null) { try { bean.destroy(); } catch (Throwable ex) { if (logger.isWarnEnabled()) { logger.warn("Destruction of bean with name '" + beanName + "' threw an exception", ex); } } } // 移除beanName的对应关系的bean Set<String> containedBeans; synchronized (this.containedBeanMap) { // Within full synchronization in order to guarantee a disconnected Set containedBeans = this.containedBeanMap.remove(beanName); } if (containedBeans != null) { for (String containedBeanName : containedBeans) { destroySingleton(containedBeanName); } } // 这个对象被其他bean依赖,也要移除依赖关系 synchronized (this.dependentBeanMap) { for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) { Map.Entry<String, Set<String>> entry = it.next(); Set<String> dependenciesToClean = entry.getValue(); dependenciesToClean.remove(beanName); if (dependenciesToClean.isEmpty()) { it.remove(); } } } // 移除当前bean与依赖其他bean的关系 this.dependenciesForBeanMap.remove(beanName); } /** * 用于加锁操作,返回singletonObjects,通过方法暴露这个对象。 */ @Override public final Object getSingletonMutex() { return this.singletonObjects; } }
-
图文详述Eureka的缓存机制/三级缓存
2022-01-06 07:41:47一、三级缓存概要 1、三级缓存分别是什么? 一级缓存(注册表)ConcurrentHashMap 二级缓存(ReadWriteMap)guava#LoadingCache 三级缓存(ReadOnlyMap)ConcurrentHashMap 注册一个服务实例 向注册表中写入服务实例... -
CPU一级缓存,二级缓存和三级缓存是什么意思? CPU缓存有什么用?
2021-07-17 06:16:21所谓的CPU缓存是CPU内部缓存的运行频率. 缓存的大小和结构对CPU速度的影响更大,因此缓存的大小也是CPU的重要性能指标之一. CPU缓存的工作效率可以远远超过内存和硬盘的速度. 以下安装主页主要介绍有关CPU缓存的知识... -
一级缓存、二级缓存、三级缓存区别是什么 详解它们的区分方法
2020-02-17 16:39:43大家都知道CPU缓存很重要,但对于缓存的具体细分却知之甚少,本文只要是关于CPU缓存的介绍,并着重描述了一级缓存、二级缓存、三级缓存区别方法。 CPU缓存 CPU缓存(Cache Memory)是位于CPU与内存之间的临时存储器... -
Spring三级缓存解决循环依赖问题详解
2022-01-20 14:03:31Spring 如何使用三级缓存解决循环依赖。通过对依赖注入、spring创建bean的过程、三级缓存的详细分析,说明了spring是如何利用Bean的生命周期来灵活解决循环依赖问题,以及使用三级缓存的必要性! -
图片三级缓存JAR包
2018-01-15 15:36:29android图片缓存中三级缓存的硬盘缓存jar包,android图片缓存中三级缓存的硬盘缓存jar包 -
Spring 为何需要三级缓存解决循环依赖,而不是二级缓存?
2022-02-25 00:12:30earlySingletonObjects, singletonFactories三级缓存去解决的,所说的缓存其实也就是三个Map 可以看到三级缓存各自保存的对象,这里重点关注二级缓存earlySingletonObjects和三级缓存singletonFactory,一级缓存... -
关于Spring的三级缓存
2022-05-06 21:50:07关于Spring的三级缓存 文章目录 关于Spring的三级缓存 前言 一、循环依赖 1.相互依赖 2.三者间依赖 3.自我依赖 二、缓存 1.一级缓存 2.二级缓存 3.三级缓存 总结 前言 spring的循环依赖,互相持有引用,使得依赖注入... -
终于把Spring三级缓存彻底看明白了
2021-10-29 17:10:50Spring大神提出了三级缓存帮助我们解决循环依赖的问题。 二. 概念说明 singletonFactories :一级缓存,存放类工厂(ObjectFactory),实例Bean通过ObjectFactory创建。 earlySingletonObjects :二级缓存,存放创建... -
SpringBean依赖和三级缓存
2020-06-11 01:04:09因此转而去创建b,将创建abean的过程挂起,当执行完b的构造方法后将其factory也放入三级缓存,此时执行b的属性填充,发现依赖a,从三级缓存中获取a的对象,并将a放入二级缓存中,之后b执行intialize初始化,最后将b... -
CPU 与 内存之间的三级缓存的实现原理
2021-06-16 21:47:53CPU 与 Memory 内存之间的三级缓存的实现原理 1.1 cache 存在的原理 引入 Cache 的理论基础是程序局部性原理,包括时间局部性和空间局部性。时间局部性原理即最近被CPU访问的数据,短期内CPU 还要访问(时间... -
Glide源码分析以及三级缓存原理
2022-02-12 16:10:34Glide是Android端开源图片加载库,能够帮助我们下载、缓存、展示多种格式图片。也是现在主流图片加载框架之一。源码内部究竟是如何实现的呢?讲解主流程,简略分析。 用法如下: Glide.with(context).load(url).... -
Spring中的“三级缓存”
2020-09-16 22:39:54Spring的“三级缓存”基础认识常见问题循环依赖代码示例Spring 中三大循环依赖场景 演示Spring 循环依赖小结“三级缓存”意义Spring 解决循环依赖原理分析Spring 容器的“三级缓存”源码解析 常见问题 循环依赖 循环... -
Spring为什么需要三级缓存解决循环依赖?二级缓存不行的吗?
2022-03-18 10:46:14Spring为什么需要三级缓存来解决循环依赖的呀? -
Spring三级缓存解决循环依赖问题及实现Aop
2021-07-28 09:30:39循环依赖 A类属性有B类,B类属性有A类,相互依赖。 依赖注入 ...Spring三级缓存 缓存 map 存储对象 一级缓存 singletonObjects 用来存放已经完全创建好的单例bean 二级缓存 earlySi -
Spring 循环依赖的源码深度探究以及三级缓存的原理【一万字】
2021-05-06 16:40:13基于最新Spring 5.x,从源码的角度详细介绍了Spring的循环依赖产生的原因,并且提供有效的解决办法。包括各种循环依赖,以及“三级缓存”。 -
Spring的三级缓存解决循环依赖
2022-05-26 21:06:32一、什么是Spring三级缓存 第一级缓存:也叫单例池,存放已经经历了完整生命周期的Bean对象。 第二级缓存:存放早期暴露出来的Bean对象,实例化以后,就把对象放到这个Map中。(Bean可能只经过实例化,属性还未... -
循环依赖之三级缓存
2020-11-11 22:23:12循环依赖之三级缓存 文章目录循环依赖之三级缓存循环依赖概念三大Map和四大方法A/B对象的迁移断点调试调试总结创建bean过程为什么构造器无法解决循环依赖解决循环依赖流程 文档参考周老师的资料 循环依赖概念 官方... -
Spring中Bean的生命周期以及三级缓存介绍
2019-10-09 09:18:05Bean的生命周期以及三级缓存介绍简述测试代码编写创建IOC容器功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中... -
spring三级缓存
2022-03-08 14:50:05spring三级缓存用来解决spring的循环依赖问题 目前循环依赖只在属性set注入且单例的情况下才能解决 构造器注入和多例的循环依赖情况下是无法解决的 提示:以下是本篇文章正文内容,下面案例可供参考 一、spring... -
Spring如何通过三级缓存解决循环依赖
2020-07-24 18:17:39Spring如何通过三级缓存解决循环依赖 Spring中有三级缓存,分别如下 singletonObjects:完成初始化的单例对象的cache(一级缓存) earlySingletonObjects :完成实例化但是尚未初始化的,提前暴光的单例对象的Cache... -
一级缓存、二级缓存、三级缓存
2019-10-02 18:39:59大家都知道CPU缓存很重要,但对于缓存的具体细分却知之甚少,本文只要是关于CPU缓存的介绍,并着重描述了一级缓存、二级缓存、三级缓存区别方法。 CPU缓存 CPU缓存(Cache Memory)是位于CPU与内存之间的临时...