關于Spring中的三級緩存解析
Spring的三級緩存
Spring三級緩存是為了解決對象間的循環(huán)依賴問題。
A依賴B,B依賴A,這就是一個簡單的循環(huán)依賴。
我們來先看看三級緩存的源碼。
(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級緩存 存儲創(chuàng)建單例BEAN的工廠 ? ? ? ? private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); ? ? ? ? //已經注冊的單例池里的beanName ? ? ? ? private final Set<String> registeredSingletons = new LinkedHashSet<>(256); ? ? ? ? //正在創(chuàng)建中的beanName集合 ? ? ? ? private final Set<String> singletonsCurrentlyInCreation = ? ? ? ? ? ? ? ? Collections.newSetFromMap(new ConcurrentHashMap<>(16)); ? ? ? ? //緩存查找bean ?如果第1級緩存沒有,那么從第2級緩存獲取。如果第2級緩存也沒有,那么從第3級緩存創(chuàng)建,并放入第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中創(chuàng)建了bean的實例后,封裝ObjectFactory放入緩存的bean實例 ? ? ? ? ? ? ? ? ? ? ? ? ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); ? ? ? ? ? ? ? ? ? ? ? ? if (singletonFactory != null) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? //創(chuàng)建未賦值的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)“創(chuàng)建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); ? ? //執(zhí)行初始化方法,并創(chuàng)建代理 ? ? exposedObject = initializeBean(beanName, exposedObject, mbd); ? ? return exposedObject; }
通過這段代碼,我們可以知道:Spring 在實例化對象之后,就會為其創(chuàng)建一個 Bean 工廠,并將此工廠加入到三級緩存中。
因此,Spring 一開始提前暴露的并不是實例化的 Bean,而是將 Bean 包裝起來的ObjectFactory。為什么要這么做呢?
這實際上涉及到 AOP。如果創(chuàng)建的 Bean 是有代理的,那么注入的就應該是代理 Bean,而不是原始的 Bean。但是,Spring一開始并不知道 Bean是否會有循環(huán)依賴,通常情況下(沒有循環(huán)依賴的情況下),Spring 都會在“完成填充屬性并且執(zhí)行完初始化方法”之后再為其創(chuàng)建代理。但是,如果出現了循環(huán)依賴,Spring 就不得不為其提前創(chuàng)建"代理對象";否則,注入的就是一個原始對象,而不是代理對象。因此,這里就涉及到"應該在哪里提前創(chuàng)建代理對象"?
Spring 的做法就是:在 ObjectFactory 中去提前創(chuàng)建代理對象。它會執(zhí)行 getObject() 方法來獲取到 Bean。實際上,它真正執(zhí)行的方法如下:
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中記錄已被代理的對象,是為了避免在后面重復創(chuàng)建代理對象。
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()方法,可知:
提前暴露的對象,雖然已實例化,但是沒有進行屬性填充,還沒有完成初始化,是一個不完整的對象。 這個對象存放在二級緩存中,對于三級緩存機制十分重要,是解決循環(huán)依賴一個非常巧妙的設計。
讓我們來分析一下“A的某個field或者setter依賴了B的實例對象,同時B的某個field或者setter依賴了A的實例對象”這種循環(huán)依賴的情景。
- A 調用doCreateBean()創(chuàng)建Bean對象:由于還未創(chuàng)建,從第1級緩存singletonObjects查不到,此時只是一個半成品(提前暴露的對象),放入第3級緩存singletonFactories。
- A在屬性填充時發(fā)現自己需要B對象,但是在三級緩存中均未發(fā)現B,于是創(chuàng)建B的半成品,放入第3級緩存singletonFactories。
- B在屬性填充時發(fā)現自己需要A對象,從第1級緩存singletonObjects和第2級緩存earlySingletonObjects中未發(fā)現A,但是在第3級緩存singletonFactories中發(fā)現A,將A放入第2級緩存earlySingletonObjects,同時從第3級緩存singletonFactories刪除。
- 將A注入到對象B中。
- B完成屬性填充,執(zhí)行初始化方法,將自己放入第1級緩存singletonObjects中(此時B是一個完整的對象),同時從第3級緩存singletonFactories和第2級緩存earlySingletonObjects中刪除。
- A得到“對象B的完整實例”,將B注入到A中。
- A完成屬性填充,執(zhí)行初始化方法,并放入到第1級緩存singletonObjects中。
在創(chuàng)建過程中,都是從第三級緩存(對象工廠創(chuàng)建不完整對象),將提前暴露的對象放入到第二級緩存;從第二級緩存拿到后,完成初始化,并放入第一級緩存。
spring三級緩存代碼流程圖
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
解決SpringBoot項目啟動后網頁顯示Please sign in的問題
這篇文章主要介紹了解決SpringBoot項目啟動后網頁顯示Please sign in的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04