關(guān)于Spring中一級緩存、二級緩存和三級緩存的那些事
題記
常常聽到別人提起:“一級緩存、二級緩存、三級緩存”。那么它們是什么呢?有什么作用呢?
緩存作用分析
Spring中的一級緩存名為singletonObjects,二級緩存名為earlySingletonObjects,三級緩存名為singletonFactories,除了一級緩存是ConcurrentHashMap之外,二級緩存和三級緩存都是HashMap。它們的定義是在DefaultSingletonBeanRegistry類中。

一級緩存-singletonObjects是用來存放就緒狀態(tài)的Bean。保存在該緩存中的Bean所實現(xiàn)Aware子接口的方法已經(jīng)回調(diào)完畢,自定義初始化方法已經(jīng)執(zhí)行完畢,也經(jīng)過BeanPostProcessor實現(xiàn)類的postProcessorBeforeInitialization、postProcessorAfterInitialization方法處理;
二級緩存-earlySingletonObjects是用來存放早期曝光的Bean,一般只有處于循環(huán)引用狀態(tài)的Bean才會被保存在該緩存中。保存在該緩存中的Bean所實現(xiàn)Aware子接口的方法還未回調(diào),自定義初始化方法未執(zhí)行,也未經(jīng)過BeanPostProcessor實現(xiàn)類的postProcessorBeforeInitialization、postProcessorAfterInitialization方法處理。如果啟用了Spring AOP,并且處于切點表達式處理范圍之內(nèi),那么會被增強,即創(chuàng)建其代理對象。
這里額外提一點,普通Bean被增強(JDK動態(tài)代理或CGLIB)的時機是在AbstractAutoProxyCreator實現(xiàn)的BeanPostProcessor的postProcessorAfterInitialization方法中,而處于循環(huán)引用狀態(tài)的Bean被增強的時機是在AbstractAutoProxyCreator實現(xiàn)的SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法中。
三級緩存-singletonFactories是用來存放創(chuàng)建用于獲取Bean的工廠類-ObjectFactory實例。在IoC容器中,所有剛被創(chuàng)建出來的Bean,默認都會保存到該緩存中。
Bean在這三個緩存之間的流轉(zhuǎn)順序為(存在循環(huán)引用):
- 通過反射創(chuàng)建Bean實例。是單例Bean,并且IoC容器允許Bean之間循環(huán)引用,保存到三級緩存中。
- 當(dāng)發(fā)生了循環(huán)引用時,從三級緩存中取出Bean對應(yīng)的ObjectFactory實例,調(diào)用其getObject方法,來獲取早期曝光Bean,從三級緩存中移除,保存到二級緩存中。
- Bean初始化完成,生命周期的相關(guān)方法執(zhí)行完畢,保存到一級緩存中,從二級緩存以及三級緩存中移除。
Bean在這三個緩存之間的流轉(zhuǎn)順序為(沒有循環(huán)引用):
- 通過反射創(chuàng)建Bean實例。是單例Bean,并且IoC容器允許Bean之間循環(huán)引用,保存到三級緩存中。
- Bean初始化完成,生命周期的相關(guān)方法執(zhí)行完畢,保存到一級緩存中,從二級緩存以及三級緩存中移除。
簡略流程圖:

一級緩存、二級緩存、三級緩存區(qū)別是什么
一級緩存、二級緩存、三級緩存是什么?作用?區(qū)別? 首先簡單了解一下一級緩存。目前所有主流處理器大都具有一級緩存和二級緩存,少數(shù)高端處理器還集成了三級緩存。其中,一級緩存可分為一級指令緩存和一級數(shù)據(jù)緩存。一級指令緩存用于暫時存儲并向CPU遞送各類運算指令;一級數(shù)據(jù)緩存用于暫時存儲并向CPU遞送運算所需數(shù)據(jù),這就是一級緩存的作用。 那么,二級緩存的作用又是什么呢?簡單地說,二級緩存就是一級緩存的緩沖器:一級緩存制造成本很高因此它的容量有限,二級緩存的作用就是存儲那些CPU處理時需要用到、一級緩存又無法存儲的數(shù)據(jù)。同樣道理,三級緩存和內(nèi)存可以看作是二級緩存的緩沖器,它們的容量遞增,但單位制造成本卻遞減。
需要注意的是,無論是二級緩存、三級緩存還是內(nèi)存都不能存儲處理器操作的原始指令,這些指令只能存儲在CPU的一級指令緩存中,而余下的二級緩存、三級緩存和內(nèi)存僅用于存儲CPU所需數(shù)據(jù)。 根據(jù)工作原理的不同,目前主流處理器所采用的一級數(shù)據(jù)緩存又可以分為實數(shù)據(jù)讀寫緩存和數(shù)據(jù)代碼指令追蹤緩存2種,它們分別被AMD和Intel所采用。不同的一級數(shù)據(jù)緩存設(shè)計對于二級緩存容量的需求也各不相同,下面讓我們簡單了解一下這兩種一級數(shù)據(jù)緩存設(shè)計的不同之處。
一、AMD一級數(shù)據(jù)緩存設(shè)計 AMD采用的一級緩存設(shè)計屬于傳統(tǒng)的“實數(shù)據(jù)讀寫緩存”設(shè)計?;谠摷軜?gòu)的一級數(shù)據(jù)緩存主要用于存儲CPU最先讀取的數(shù)據(jù);而更多的讀取數(shù)據(jù)則分別存儲在二級緩存和系統(tǒng)內(nèi)存當(dāng)中。做個簡單的假設(shè),假如處理器需要讀取“AMD ATHLON 64 3000+ IS GOOD”這一串?dāng)?shù)據(jù)(不記空格),那么首先要被讀取的“AMDATHL”將被存儲在一級數(shù)據(jù)緩存中,而余下的“ON643000+ISGOOD”則被分別存儲在二級緩存和系統(tǒng)內(nèi)存當(dāng)中(如下圖所示)。 需要注意的是,以上假設(shè)只是對AMD處理器一級數(shù)據(jù)緩存的一個抽象描述,一級數(shù)據(jù)緩存和二級緩存所能存儲的數(shù)據(jù)長度完全由緩存容量的大小決定,而絕非以上假設(shè)中的幾個字節(jié)。“實數(shù)據(jù)讀寫緩存”的優(yōu)點是數(shù)據(jù)讀取直接快速,但這也需要一級數(shù)據(jù)緩存具有一定的容量,增加了處理器的制造難度(一級數(shù)據(jù)緩存的單位制造成本較二級緩存高)。
二、Intel一級數(shù)據(jù)緩存設(shè)計 自P4時代開始,Intel開始采用全新的“數(shù)據(jù)代碼指令追蹤緩存”設(shè)計?;谶@種架構(gòu)的一級數(shù)據(jù)緩存不再存儲實際的數(shù)據(jù),而是存儲這些數(shù)據(jù)在二級緩存中的指令代碼(即數(shù)據(jù)在二級緩存中存儲的起始地址)。假設(shè)處理器需要讀取“INTEL P4 IS GOOD”這一串?dāng)?shù)據(jù)(不記空格),那么所有數(shù)據(jù)將被存儲在二級緩存中,而一級數(shù)據(jù)代碼指令追蹤緩存需要存儲的僅僅是上述數(shù)據(jù)的起始地址。
由于一級數(shù)據(jù)緩存不再存儲實際數(shù)據(jù),因此“數(shù)據(jù)代碼指令追蹤緩存”設(shè)計能夠極大地降CPU對一級數(shù)據(jù)緩存容量的要求,降低處理器的生產(chǎn)難度。但這種設(shè)計的弊端在于數(shù)據(jù)讀取效率較“實數(shù)據(jù)讀寫緩存設(shè)計”低,而且對二級緩存容量的依賴性非常大。 在了解了一級緩存、二級緩存的大致作用及其分類以后,下面我們來回答以下硬件一菜鳥網(wǎng)友提出的問題。
從理論上講,二級緩存越大處理器的性能越好,但這并不是說二級緩存容量加倍就能夠處理器帶來成倍的性能增長。目前CPU處理的絕大部分數(shù)據(jù)的大小都在0-256KB之間,小部分數(shù)據(jù)的大小在256KB-512KB之間,只有極少數(shù)數(shù)據(jù)的大小超過512KB。所以只要處理器可用的一級、二級緩存容量達到256KB以上,那就能夠應(yīng)付正常的應(yīng)用;512KB容量的二級緩存已經(jīng)足夠滿足絕大多數(shù)應(yīng)用的需求。 這其中,對于采用“實數(shù)據(jù)讀寫緩存”設(shè)計的AMD Athlon 64、Sempron處理器而言,由于它們已經(jīng)具備了64KB一級指令緩存和64KB一級數(shù)據(jù)緩存,只要處理器的二級緩存容量大于等于128KB就能夠存儲足夠的數(shù)據(jù)和指令,因此它們對二級緩存的依賴性并不大。這就是為什么主頻同為1.8GHz的Socket 754 Sempron 3000+(128KB二級緩存)、Sempron 3100+(256KB二級緩存)以及Athlon 64 2800+(512KB二級緩存)在大多數(shù)評測中性能非常接近的主要原因。所以對于普通用戶而言754 Sempron 2600+是值得考慮的。 反觀Intel目前主推的P4、賽揚系列處理器,它們都采用了“數(shù)據(jù)代碼指令追蹤緩存”架構(gòu),其中Prescott內(nèi)核的一級緩存中只包含了12KB一級指令緩存和16KB一級數(shù)據(jù)緩存,而Northwood內(nèi)核更是只有12KB一級指令緩存和8KB一級數(shù)據(jù)緩存。
因此,P4、賽隆系列處理器非常依賴于二級緩存,賽揚D 320(256KB二級緩存)和賽揚2.4GHz(128kb二級緩存)的性能差距是很好的證明;Cayon D和P4E處理器之間的性能差距也非常明顯。最后,如果你是一個狂熱的游戲愛好者或者一個專業(yè)的多媒體用戶,一個帶有1MB二級緩存的P4處理器和一個512Kb/1MB二級緩存的Athon 64處理器是你的理想選擇。由于CPU的主存和二級緩存在重計算負載下幾乎是“滿”的,大的二級緩存可以為處理器提供大約5%到10%的性能改進,這對于要求苛刻的用戶是絕對必要的。一級緩存是在CPU內(nèi)的,用來存放內(nèi)部指令,2級緩存和CPU封裝在一起,也是用來存放指令數(shù)據(jù)的,三級和四級緩存只在高端的服務(wù)器CPU里有,作用差不多,速度更快,更穩(wěn)定,更有效 并不是緩存越大越好,譬如AMD和INTER就有不同的理論,AMD認為一級緩存越大越好,所以一級比較大,而INTER認為過大會有更長的指令執(zhí)行時間,所以一級很小,二級緩存那兩個公司的理論又反過來了,AMD的小,INTER的大,一般主流的INTERCPU的2級緩存都在2M左右 我們通常用(L1,L2)來稱呼緩存又叫高速緩沖存儲器其作用在于緩解主存速度慢、跟不上CPU讀寫速度要求的矛盾。它的實現(xiàn)原理,是把CPU最近最可能用到的少量信息(數(shù)據(jù)或指令)從主存復(fù)制到CACHE中,當(dāng)CPU下次再用這些信息時,它就不必訪問慢速的主存,而直接從快速的CACHE中得到,從而提高了得到這些信息的速度,使CPU有更高的運行效率。
總結(jié)
通過以上分析,我們可以得知Bean在一級緩存、二級緩存、三級緩存中的流轉(zhuǎn)順序為:三級緩存->二級緩存->一級緩存。但是并不是所有Bean都會經(jīng)歷這個過程,例如對于原型Bean(Prototype),IoC容器不會將其保存到任何一個緩存中的,另外即便是單例Bean(Singleton),如果沒有循環(huán)引用關(guān)系,也不會被保存到二級緩存中的。
到此這篇關(guān)于關(guān)于Spring中一級緩存、二級緩存和三級緩存的那些事的文章就介紹到這了,更多相關(guān)Spring一級緩存、二級緩存和三級緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決idea中java出現(xiàn)無效的源發(fā)行版問題
這篇文章主要給大家介紹了關(guān)于解決idea中java出現(xiàn)無效的源發(fā)行版問題的相關(guān)資料,無效的源發(fā)行版是指IntelliJ IDEA無法正確識別和處理的源代碼版本,這可能是由于錯誤的配置、缺少依賴項、不兼容的插件或其他問題導(dǎo)致的,需要的朋友可以參考下2024-01-01
解決Springboot獲取不到nacos配置中心的配置問題
由于項目使用的nacos老版本,存在風(fēng)險bug, 需要將nacos升級至2.2.1及以上版本,版本升級完畢之后 啟動項目發(fā)現(xiàn)項目開始報錯,所以本文記錄一下Springboot獲取不到nacos配置中心的配置問題,文中有詳細的解決方法,需要的朋友可以參考下2023-09-09
Java使用XML與注解方式實現(xiàn)CRUD操作代碼
MyBatis提供了靈活的配置和使用方式,使得數(shù)據(jù)庫操作更加簡潔和高效,通過本文,我們介紹了如何使用MyBatis框架,通過XML映射文件和注解兩種方式來實現(xiàn)數(shù)據(jù)庫的增刪改查操作,感興趣的朋友跟隨小編一起看看吧2024-02-02
springboot整合sentinel接口熔斷的實現(xiàn)示例
為了防止慢接口導(dǎo)致的服務(wù)阻塞,可以通過添加熔斷處理來避免應(yīng)用的大量工作線程陷入阻塞,保證其他接口的正常運行,本文介紹了如何使用Spring Boot與Sentinel進行接口熔斷的配置與實現(xiàn),感興趣的可以了解一下2024-09-09
MyBatis Map結(jié)果的Key轉(zhuǎn)為駝峰式
今天小編就為大家分享一篇關(guān)于MyBatis Map結(jié)果的Key轉(zhuǎn)為駝峰式,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12
JAVA復(fù)制數(shù)組和重置數(shù)組大小操作
這篇文章主要介紹了JAVA復(fù)制數(shù)組和重置數(shù)組大小操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09

