寫本身的緩存框架,JAD-CACHE架構設計篇

    在以前一篇《寫一個本身的通用緩存框架,以同時支持ehcache、mecache以及springcache註解等等》博文中,列出了本身的通用緩存框架須要實如今的大體功能總結以下:git

    一、提供統一的緩存操做api;spring

    二、支持同時使用多種緩存實現;設計模式

    三、提供靈活的配置;api

    四、須要防止緩存穿透;緩存

    五、須要能夠靈活指定緩存存活時間;服務器

    六、須要任意控制緩存的停用或啓用。微信

    目前這個框架的編碼部分已完成,並取名爲JAD-CACHE,取這個名字的緣由是由於它是個人我的的JAD項目的一部分,JAD項目是本人用業餘時間開發一個企業基礎架構平臺,因涉及的東西比較多,並且不少模塊尚未徹底完成。目前準備把其中作的比較完善的緩存模塊單獨從原項目中剝離出來做爲一個獨立的項目並準備開源給你們測試和使用,因而也就有了JAD-CACHE。架構

     本文先展現這個框架的原理及架構設計,後續開放源代碼後再發布一些使用手冊方面的文章。框架

     JAD-CACHE緩存框架是在spring cache模塊的基礎上擴展而來,在上一篇博文《通用緩存框架,spring緩存模塊原理分析篇》已經系統分析過srping cache的原理,這裏再也不重複。spring cache模塊重要的兩個類就是org.springframework.cache.Cache和 org.springframework.cache.CacheManager。如今我跟據本身的須要對它們進行擴展。測試

    我設計的Cahce相關的擴展類圖以下:

圖:Cahce擴展類類圖1

       上圖中灰色部分是spring自已的類,其它的是擴展出來的。上圖ManageredCache是一個接口,表示這個Cache可由本框架的CacheClient實例管理起來(關於CacheClient的概念稍後介紹)。ManageredCache接口在父接口Cache的基礎上,增長了isAllowNullValues()等等方法,做用分別以下:

getCacheClient()

得到管理它的CacheClient實例

isAllowNullValues()

可否在此緩存中保存null值,防止緩存穿透

getActivityTime()

得到此緩存中對像存活時間,注意這個存活時間是一個業務存活時間,開發人員可經過配置指定一個默認的時間,也能夠在調用put()方法緩存對像時經過參數另外指定一個存活時間。這樣,在調用get()方法從緩存中取出對像後,會先經過個這個方法判斷對像是否失效(即便它依舊存在於緩存中,但咱們能夠在業務的角度上覺得它失效了),這個存活時間應該短於用戶在ehcache.xml等配置文件配置的存活時間,這樣就實現了個性化指定同一類型不一樣對像的存活時間。

put(Object, Object,int)

這個方法跟父類Cache接口的put(Object,Object)功能相同,就是把對像緩存起來,但它支持一個int類型的參數,用於指定對像存活時間的秒數。

size()

統計對像總數

keySet()

得到全部key

    全部要緩存的數據都不是直接持久化到緩存容器中的,而是被裝包成了一個個CacheValue類型的實例,在上圖的類圖中,能夠看到,CacheValue類包含兩個屬性expiryTime和value,其中expiryTime是超時時間,value就是據體的數據對像。若是數據對像爲null值,就轉換成NullCacheData實例。在AbstractManageredCache這個抽象類的相關方法中,就實現了這些邏輯。

     AbstractManageredCache是對ManageredCache接口的抽象實現,實現了在操做緩存以前,先經過管理它的CacheClient實例判斷當前緩存客戶端的狀態是否已開啓 (調用cacheClient的isStarted()方法),若是啓用,就調用父接口Cache中聲明的getNativeCache()得到具體的緩存實例操做緩存,若是沒有啓用,就什麼也不作。同時,在它的put()方法實現過程當中,會跟據它的activityTime屬性指定存活時間,或跟據allowNullValues屬性決定是否緩存null值,並將全部要緩存的數據包裝成CacheValue實例持久化到緩存容器中。而在get()方法實現的羅輯,也會作相應的操做,跟據activityTime屬性踢出超時的對像,並將緩存容器中的CacheValue實例轉換成原始的數據類型。

    在spring原來的緩存模型中,全部的Cache實例都被ManagerCache所管理。但本框架抽像出了一個叫CacheClient的概念,全部的緩存實例都被擴展成了ManageredCache對像,並被一個CacheClient實例管理起來(而此CacheClient實例又持有一個CacheManager的引用,這樣一來Cache也就能夠經過CacheClient間接的被ManagerCache管理)。這樣作有一個好處就是:在Cache操做緩存以前,先經過它的CacheClient判斷當前的緩存狀態,跟據這個裝態決定是否要進行操做。設計CacheClinet還有一個目地,就是讓多個緩存實現能更好的共存於同一個應用之中,好比讓EhCache實現的緩存交給一個CacheClinet管理,讓MemCache實現的緩存交給另外一個CacheClinet管理。在spring原來的緩存模塊中,設計了一個叫CompositeCacheManager的類,能夠同時配置多個CacheManager實例以達到這個目地。但我棄用它,改用CacheClinet的目地,就是想增長能夠任意停用或啓用某些Cache的功能。好比,當memcache服務器掛掉時,咱們經過它對應的CacheClinet實例改變這個實例管理的全部Cache的狀態,停用它,從而達到從應用層上禁用或啓用緩存的目地。CacheClient相關的類圖以下:

圖:CacheClient相關類圖

    上圖中的CacheClient類是一個接口,它聲明的一些諸如start(),stop()等方法,用於修改本實例的狀態,啓用或停用,而isStarted()就是用來檢查狀態的,返回當前Client是否啓用。每個CacheClient實例管理一個CacheManager,經過該接口中的getCacheManager()能夠得到它所控制的CacheManager實例引用,每一個一個實例有一個惟一的名字,經過getClientName()能夠獲取它的名字。除此外,此接口還有一些諸如getAllowNullValues(),setDefActivityTime()之類的方法。這是爲了方便開發人員對緩存的配置,開發人員在配置CacheClient實例時,能夠在這裏配置allowNullValues, defActivityTime等屬性,這樣再在配置CacheManager或者Cache實例時就能夠不指定了這些屬性了,Cache會自動繼承它的Client的屬性值。這些配置在CacheClient接口的抽像實現類AbstractCacheClient中都有相應的實現。

     在AbstractCacheClient中還有一個重要的屬性,就是autoStart屬性。這個屬性若是配置爲true,那在spring容器初始化的時候,這個Client實例一但生成,就會自動調用它的start()啓動它,以使得它所控制的CacheManager能夠正常操做緩存。不然,它不會自動啓動,它所控制的全部Cache都處於禁用狀態。

    另外,爲了方便配置,在AbstractCacheClient還提供了autoCreateCache屬性,用於指定此客戶端可否自動建立緩存實例。在Spring原來的緩存配置中,須要把用到的每一個Cache都寫到配置文件中,要麼配到ehcache.xml中,要麼在配置CacheManager時附加Cache實列相關的配置。不然,在操做沒有配置的緩存時,會提示找不到某某名稱的cache。在本框架中,若是指定了autoCreateCache屬性爲true,在調用CacheManager.getCache(String name)獲取不到Cache時,會自動建立一個默認的(經過覆蓋CacheManager.getMissgeCache()實現)。固然,若是指定autoCreateCache爲false時,就不會自動建立,這要求用戶在ehcache.xml中本身配置。固然,爲了方便,本框架,還能夠直接在CacheClient中配置,上面的類圖AbstractCacheClient中兩個屬性cacheNames和cacheBeans就是用於這個配置的。用戶可經過cacheNames只配置名稱,或者經過cacheBeans屬性配置一個類型爲的JadCache實例bean。這個JadCache相似於spring 在實現ehcache時提供的EhCacheFactoryBean。只不過這個更加簡潔通用。若是隻經過cacheNames配置一個Cache的名稱,那麼此Cache實例的相關屬性都採用默認值這要求用戶在ehcache.xml配置文件中配置一個defaultCache,或須要在memcache.xml中配置一個默認的cacheclient。

    每個CacheClient惟一管理一個CacheManager實例(在上面類圖中能夠看到,AbstractCacheClient類中有一個JadCacheManager類型的屬性:cacheManager。關於本框架的CacheManager擴展稍後介紹)。CacheClient在被spring初始化時,會自動調用registryCacheManager()方法,跟據不一樣的緩存實現廠商生成一個對應的CacheManager實例,並註冊到spring context中,同時調用initCache()方法經過配置中的cacheNames或cacheBeans自動初始化全部的Cache實例。初始化完成後,再調用registryToMasterCacheManager()方法,這個方法稍後介紹。

    一個應用系統中,能夠有一個或多個CacheClient實例,每一個CacheClient實例控制一個CacheManger。開發人員經過配置不一樣的CacheClient實例能夠實現同時支持多個不一樣的緩存實現,好比,把EhCache相關的緩存配置到一個CacheClient中而把MemCache配置到另外一個CacheClient中。

    爲了統一管理全部CacheClient實例,本框架設計了一個叫CacheClientManager來管理所CacheClient實例,它有一個抽像實現AbstractCacheClientManager,這個抽像類中,也有allowNullValues, defActivityTime等CacheClient中具的相同的屬性,只不過這裏的屬性做爲一個全局的配置,使得CacheClient能夠省去這些配置而直接使用CacheClientManager中的配置。整個應用中,只能有CacheClientManager實例,但這個實例能夠管理一個或多個CacheClient。而一般況下,一些簡單的應用系統中,每每只有一種緩存實現,也就是隻須要配置一個CacheClient,所以AbstractCacheClientManager給出了兩個不一樣的實現類,分別是上圖中紅顏色的SingleClientManager和MultiClientManager,分別表示單CacheClient管理或多CacheClient管理器。開發人員可跟據業務狀況選擇性使用其中一個進行配置。

    前文提到,每一個CacheClient在初始化時,會自動生成一個對應的CacheManager實例並註冊到Spring上下文中,但Spring在操做緩存時,爲了能準確的經過CacheManager找到相應名稱的Cache實例,這就要求還須要對這些CacheManager實例進行統一管理。在spring原來的緩存模塊中,提供了一個叫CompositeCacheManager的實現類,以組合設計模式的方式來管理這些CacheManager實例,這個CompositeCacheManager實現類有一個列表指向全部CacheManager實例的引用。在執行getCache(String)時會遍歷這個列表,循環調用每一個實例的getCache(String)方法,而後返回一個不爲null的Cache,可是若是全部的CacheManager都獲取不到Cache時,這個方法最終是會返回null的。然而,在本框架中,是支持找不到Cache時自動建立的,因此在本框架中,我設計了一個叫MasterCacheManager的類來管理這些CacheManager,同時,這個類有一個叫defCacheManager的CacheManager屬性來指定一個默認的CacheManager。在跟據名稱找不到任何Cache時,就自動調用這個默認CacheManager的addCache()方法來自動建立一個。本框架CacheManager相關的類圖以下所示:

圖:CacheManager類圖

    上圖灰色總分是spring緩存模塊自帶的類,其它顏色是擴展類。其中最右邊的MasterCacheManager類就是上文提到管理全部CacheManager的實現類。上圖左邊的JadCacheManager是一個接口,提供initCache(JadCache)和newCache(JadCache)兩個方法,這兩個方法,主要是用於在CacheClient初始化過程自動生成CacheManager實現類後,準備經過initCache()方法來初始化配置中的Cache來調用的。對於MasterCacheManager類的實例化,開發人員無需額外在spring context中配置,由於在CacheClientManager的初始化過程當中,會自動註冊一個MasterCacheManager類型的實例到spring context中(上面類圖AbstractCacheClientManager這個類中的registerMasterManager()方法就是用來作這個事的)。而這個類中cacheManagerMap的屬性就是按名稱組織起來的CacheManager類型的集合。在每一個CacheClient初始化時自動生成CacheManager實例後,會調用CacheClient類的registryToMasterCacheManager()方法,這個方法會從當前Spring conetxt中獲取到MasterCacheManager實例,而後調用它的register()方法,把它註冊到MasterCacheManager實例中(添加到cacheManagerMap集合)。

上面類圖中的JadAbstractCacheManger是借用了Srping的AbstractCacheManger對JadCacheManager的一個抽象實現,後面在集成EhCache或MemCache等全部緩存時就從這個類往下擴展。

以上就是本框架的一個整體設計,由於篇附過長。後面再在其它的文章中給出在這個基礎上擴展EhCache和MemCache的方案,並實現一個基於Map的內存緩存實現。  

目前JAD-CACHE項目已在開源中國碼雲平臺上開源,地址:

https://git.oschina.net/457049726/jad-cache

想關注更多信息或者想及時瞭解動態的同窗們能夠掃如下二維碼關注個人微信公衆號,多謝

相關文章
相關標籤/搜索