Springboot中的緩存Cache和CacheManager原理介紹

背景理解

什麼是緩存,爲何要用緩存

程序運行中,在內存保持必定時間不變的數據就是緩存。簡單到寫一個Map,裏面放着一些key,value數據,就已是個緩存了html

因此緩存並非什麼高大上的技術,只是個概念,把要屢次使用的東西存在一個變量裏,時不時取出來使用,就達到了緩存的目的,緩存就是存放數據的容器java

那爲何要用緩存呢,是由於要屢次使用。一個程序總有一些數據時可預見被屢次使用(預見的準不許就是常說的命中率)redis

好比一個複雜的計算結果,一次數據庫訪問取得的數據等耗時耗資源的數據就能放入緩存,目的就是爲了節省開銷,咱們要用有限的資源(CPU,內存,帶寬等等)儘可能作最多的事情。數據庫

爲何要用SpringCache(緩存的演變過程)

緩存的思考

若是咱們要設計一個緩存,最基本的功能是存和取:緩存

1.能在緩存裏存放數據安全

2.能在緩存裏取出數據工具

但是這不夠呀,好比如下的思考學習

1.取數據時判斷,數據是否存在,若是不存在是否是要數據庫取spa

2.若是是過時的內容是否是要更新設計

3.若是我有多個緩存,一個是我本身設計的HashMap緩存,一個是名聲很大的redis,還有....,那須要個緩存管理器呀

爲了讓緩存更好用,更「智能」,愈來愈多的需求就會被提出來,而緩存就是這樣一步步演變直到SpringCache橫空出世,功能十分強大(說白了就是咱們少寫不少代碼)

SpringCache的好處

SpringCache包含兩個頂級接口,Cache(緩存)和CacheManager(緩存管理器),顧名思義,用CacheManager去管理一堆Cache。

最最關鍵的地方:抱緊了Spring的大腿,可使用註解就能完成數據進入緩存!!

給你們舉個例子,就知道多簡單了

首先,Springboot中會自動加載一個CacheManager(它有默認的實現類),因此只要寫好一個自定義的Cache便可(若是想用系統定義好的或者第三方如RedisCache也行,記得向Spring註冊這個bean便可)

@Component
public class MyCache implements Cache {
  /*
       實現接口方法,一些關於數據set和get的方法
       CacheManager是根據Cache的名字進行管理的
       因此假設這個Cache名爲MyCache
  */  
}

而後在得出數據的方法上寫上註釋便可

@Cacheable(value = "MyCache",key = "#id")
public String getNavegationURLs(String id) {
        //一個獲取數據的方法
}

這樣就會在調用這個方法時,會以id爲key值,在名爲MyCache的Cache容器中查找(註解中value就是緩存名字,不一樣名字指定使用不一樣的緩存)

若是沒查到,則執行方法 getNavegationURLs,將返回值存入緩存

若是找到了,就直接將從緩存取值,直接返回,不用執行方法 getNavegationURLs

還有其餘方便的Cache註解自行百度,重要的是咱們根本不用寫任何關於調用緩存的邏輯代碼,只用關注於緩存自身的邏輯

註解如何起做用的,源碼流程大體瞭解

爲何要了解源碼

最直接的緣由是由於SpringCache是不支持靈活的緩存時間設置的,因此想了解大概的前因後果去實現一個支持緩存過時時間設置和自動更新的類(以後會寫實現博文)。

高大上的緣由是想經過此次探索,去了解下Spring對類的管理機制,去接觸下AOP的實現

SpringCache源碼簡單分析

你們從上面例子有沒發現問題,Cache和CacheManager是怎樣作關聯的,實際上是Spring掃包實現的

凡是繼承了Cache接口的類,都會被自動注入進CacheManager中,最終存儲於CacheManager的實現類中

 

 接着會生成被@Cacheable(或者其餘SpringCache註解修飾過)的代理類,並會將管理它的CacheManager賦值進去

 看這段代碼,就知道若是要設置多個CacheManager,就得在衆多實現類的其中一個加上@Primary,否則會Spring會報錯能選擇的Bean太多而不知道用哪一個

 

代理類生成後(包括會根據不一樣的註解生成信息類CacheOperationMetadata,到時候就會根據這個類的內容進行緩存操做,說白了就是調用咱們實現Cache裏面的各類方法)

Springboot底層初始化完成後,進入咱們寫的代碼邏輯

若是這時進入了該類的方法,如:

 

 代碼跟進去,你會神奇的發現進入了代理類的intercept方法,怎麼進去的呢~(具體原理看下面3.0)

 這裏面就會根據註解類型,進行緩存的邏輯判斷,而後決定會不會調用咱們寫的方法~

 代理類原理介紹(AOP切面之類的都是經過代理哦)

Spring代理分爲兩種:

1.JDK原生動態代理,要求被代理的類須要實現接口(經過接口來實現的代理

那麼代理類知足如下條件:

首先實現一個InvocationHandler,方法調用會被轉發到該類的invoke()方法。
意思是:對代理對象的全部接口方法調用都會轉發到InvocationHandler.invoke()方法,在invoke()方法裏咱們能夠加入任何邏輯,好比修改方法參數,加入日誌功能、安全檢查功能等;以後咱們經過某種方式執行真正的方法體
 
2.CGLIB動態代理,不要求被代理的類須要實現接口,可是final的方法沒法被代理( 經過繼承來實現代理
那麼代理類知足如下條件:
實現一個MethodInterceptor,方法調用會被轉發到該類的intercept()方法

具體內容能夠參考這篇精品博客:http://www.javashuo.com/article/p-wtdaezwq-ke.html

若是你想本身實現代理類(就是不喜歡用工具包),其實也行啊,輸出符合class規範的二進制字節碼就行啦~~~(認真學習JVM規範吧)

 

至此,該分享的就分享完啦,有什麼問題歡迎留言一塊兒探討~

相關文章
相關標籤/搜索