本文大綱 一、簡介 二、緩存的概念 三、自定義實現緩存機制 四、什麼是Ehcache 五、Ehcache怎麼用 六、Spring對緩存的支持 七、Spring+Ehcache實現 八、Spring+Shiro+Ehcache實現 九、總結 一、簡介 在項目中,用到Shiro來做驗證授權的控制。但在實 ...
本文大綱
- 一、簡介
- 二、緩存的概念
- 三、自定義實現緩存機制
- 四、什麼是Ehcache
- 五、Ehcache怎麼用
- 六、Spring對緩存的支持
- 七、Spring+Ehcache實現
- 八、Spring+Shiro+Ehcache實現
- 九、總結
一、簡介
在項目中,用到Shiro來做驗證授權的控制。但在實際使用的時候,發現用戶每訪問一個功能,都會重新到UserRealm中獲取一次許可權。這樣子會花費大量的系統系統。此時就想到了使用緩存,查了一下,Shiro也確實支持Authorization和Authentication做緩存,那就果斷使用。
但說到緩存,究竟是怎麼一回事呢?這裡我將從零開始向大家介紹一下緩存。由於網上已經有很多具體實現的文章了,本文內容是對緩存知識的逐步進階整理,目的是讓大家能從零開始對緩存進行瞭解,直到懂得如何實現Spring+Shiro+Ehcache的緩存配置。文章中不會重覆網上能找到的一大堆內容,並會給出相關的參考文章給大家參考。
二、緩存的概念
1、緩存簡介
緩存,簡單來說,就是讓數據更接近於使用者。工作機制是:先從緩存中讀取數據,如果沒有再從慢速設備上(如資料庫)讀取實際數據(數據也會存入緩存)。
2、緩存策略
緩存中數據都有一定的生命周期,什麼時候移除、什麼時候到期,都有一定的講究。主要分下麵三點。
2.1 移除策略
移除策略,即如果緩存滿了,從緩存中移除數據的策略;常見的有LFU、LRU、FIFO:
FIFO(First In First Out):先進先出演算法,即先放入緩存的先被移除;
LRU(Least Recently Used):最久未使用演算法,使用時間距離現在最久的那個被移除;
LFU(Least Frequently Used):最近最少使用演算法,一定時間段內使用次數(頻率)最少的那個被移除;
2.2 TTL(Time To Live )
存活期,即從緩存中創建時間點開始直到它到期的一個時間段(不管在這個時間段內有沒有訪問都將過期)
2.3 TTI(Time To Idle)
空閑期,即一個數據多久沒被訪問將從緩存中移除的時間。
3、參考資料
可參看此文的緩存簡介:http://jinnianshilongnian.iteye.com/blog/2001040
三、自定義實現緩存機制
1 實現步驟
實現簡單的緩存機制,通常只需實現下麵四點:
- 確定用什麼來做cache,通常使用ConcurrentHashMap鍵值對來做cache。
-
創建緩存管理器CacheManager,緩存管理器主要實現以下內容:
- 創建一個cache併進行管理
- 通過key來獲取value的方法
- 根據key更新或新增緩存中的記錄的方法
- 根據key來刪除緩存中一條記錄的方法
- 清空緩存中的所有記錄的方法
- 在Service實現類中,當查詢內容的時候,先查詢緩存中的內容,若有,則返回;若無,則查詢資料庫中的內容,同時將查詢結果加到緩存中。
- 在資料庫數據有更新的時候,註意調用方法更新緩存中的數據。
只要選擇好cache,和創建好CacheManager,就可以在Service中,通過創建CacheManager來管理緩存了。
2 存在問題
但我們自己做出來的緩存由於比較簡單考慮得沒那麼全面,所以問題也不少,如:
- 與業務邏輯代碼耦合度很高,需要在Service的方法中調用CacheManager的很多邏輯,不便於維護。
- 程式不夠靈活,無法根據不同的條件進行緩存。
- 沒有完善的移除策略,需要開發人員在業務邏輯中進行控制,難以維護。
- 不通用,無法使用第三方提供的緩存框架。
等等。
3 參考資料
由於網上已有很多實現的文章,這裡不做重覆。例如可參考:
http://blog.csdn.net/fanzhanwei/article/details/44958297
四、什麼是Ehcache
上一節是自定義緩存的實現,可以看出,自己可以做一個簡單的緩存,但是不夠完善。其實已經有很多第三方的緩存框架,有完善的機制,可以給我們使用,而ehcache就是這樣一種緩存框架。
1 Ehcache簡介
EhCache是一個純Java的進程內緩存框架,具有快速、精幹等特點,也是Hibernate中預設的CacheProvider。它會把查出來的數據存儲在記憶體或者磁碟中,以節省查詢資料庫的壓力。
2 Ehcache使用條件
-
比較少更新的表數據
因為如果更新很頻繁的數據,那就沒有緩存的必要了,可能還會增加開銷呢。
-
對數據一致性要求不高的情況
聽說Ehcache的同步不是很完善,會造成不同伺服器上的Ehcache緩存同步未必及時,這樣可能會造成用戶在獲取數據的時候不一致。
3 Ehcache使用場景
- 頁面緩存
- 對象緩存
- 資料庫數據緩存
五、Ehcache怎麼用
1 Ehcache使用步驟
使用Ehcache,基本步驟如下:
- 創建一個ehcache.xml的配置文件,裡面會有磁碟緩存位置、緩存配置等信息。
-
創建CacheManager,並讀取相應的xml配置
- 直接CacheManager cacheManage = new CacheManager(),讀取預設配置文件。
- 通過靜態方法create()創建,載入預設配置。
- 通過newInstance()工廠方法創建,newInstance()會有幾個重載,可以傳入String、URL、InputStream等來載入配置文件。
- 創建Cache,可以在ehcache.xml等配置文件中配置好,也可以直接通過API創建cache,然後通過cacheManager.addCache()方法將cache加到緩存管理器中。
- 通過cacheManager.getCache()方法獲取Cache
- 創建Element對象,存放鍵值對。
- 將創建的Element對象存放到cache中。
- 通過以上步驟,就已經把緩存弄好並存了相關內容到緩存中了。要想獲得緩存中的內容,就逆向操作,先使用cache.get()把Element獲取出來,接著通過Element.getObjectValue()獲取到相應的值。
2 Ehcache配置文件
關於配置文件,預設情況下會載入classpath下名為ehcache.xml的配置文件。如果載入失敗,會載入Ehcache報中的ehcache-failsafe.xml文件,這個文件中含有簡單的預設配置。
在ehcache.xml配置文件中,需要瞭解各參數的意思,以下是一個範例:
- name:緩存名稱。
- maxElementsInMemory:緩存最大個數。
- eternal:緩存中對象是否為永久的,如果是,超時設置將被忽略,對象從不過期。
- timeToIdleSeconds:置對象在失效前的允許閑置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,預設值是0,也就是可閑置時間無窮大。
- timeToLiveSeconds:緩存數據的生存時間(TTL),也就是一個元素從構建到消亡的最大時間間隔值,這隻能在元素不是永久駐留時有效,如果該值是0就意味著元素可以停頓無窮長的時間。
- maxEntriesLocalDisk:當記憶體中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁碟中。
- overflowToDisk:記憶體不足時,是否啟用磁碟緩存。
- diskSpoolBufferSizeMB:這個參數設置DiskStore(磁碟緩存)的緩存區大小。預設是30MB。每個Cache都應該有自己的一個緩衝區。
- maxElementsOnDisk:硬碟最大緩存個數。
- diskPersistent:是否在VM重啟時存儲硬碟的緩存數據。預設值是false。
- diskExpiryThreadIntervalSeconds:磁碟失效線程運行時間間隔,預設是120秒。
- memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理記憶體。預設策略是LRU(最近最少使用)。你可以設置為FIFO(先進先出)或是LFU(較少使用)。
- clearOnFlush:記憶體數量最大時是否清除。
3 參考資料
具體例子可參考此網站:http://www.cnblogs.com/jingmoxukong/p/5975994.html
六、Spring對緩存的支持
1 Spring配置
Spring本身有對緩存方案的簡單實現,可通過註釋驅動來實現緩存機制。緩存中,最重要的兩個概念就是CacheManager和Cache,Spring中的實現分別是:
- CacheManager:org.springframework.cache.support.SimpleCacheManager
- Cache:org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean
另外加上緩存的註解驅動配置:<cache:annotation-driven />
所以關鍵的spring xml配置文件如下:
2 重要註釋
在Spring緩存中,關鍵是在方法中增加@Cacheable、@CachePut、@CacheEvict三個註釋,然後方法內註意實現業務邏輯就好,無需像《第二部分:自定義實現緩存機制》那樣子要參雜很多的緩存管理邏輯,這就是第三方緩存框架的一大好處。實際上Spring是通過Spring AOP,在方法的調用前後,分別攔截參數和返回值,來實現緩存的錄入的。關於上面上個註釋的作用如下:
- @Cacheable:主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存。
- @CachePut:主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存,和@Cacheable不同的是,它每次都會觸發真實方法的調用。
- @CacheEvict,主要針對方法配置,能夠根據一定的條件對緩存進行清空。
具體例子可參考此網站:https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/
七、Spring+Ehcache實現
Spring cache能滿足一些基本的緩存需求,但如果需求複雜了,用戶量上去了,或者性能要求高了,Spring cache就估計難以支持了。因為它不支持高可用性,也不具備持久化數據的能力,這個時候就需要用到第三方的緩存方案,但還是用Spring的API,代碼無需改動。這就是最理想的狀態了,而Spring也支持這一點。
要配置實用Ehcache,主要改動Spring的xml配置文件,將cacheManager這個bean的具體實現由org.springframework.cache.support.SimpleCacheManager改為org.springframework.cache.ehcache.EhCacheCacheManager,並引用org.springframework.cache.ehcache.EhCacheManagerFactoryBean這個bean。此兩個類的作用:
org.springframework.cache.ehcache.EhCacheManagerFactoryBean:載入Ehcache配置文件。
org.springframework.cache.ehcache.EhCacheCacheManager:支持net.sf.ehcache.CacheManager。
配置文件如下:
具體例子可參考此網站:http://www.cnblogs.com/jingmoxukong/p/5975994.html
八、Spring+Shiro+Ehcache實現
1 配置cacheManager
如果要集成Shiro,這裡又得在Spring的xml配置文件中修改一下cacheManager的實現類,將其改為org.apache.shiro.cache.ehcache.EhCacheManager。如下:
<!-- 緩存管理器 使用Ehcache實現 --> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> </bean>
這樣就可以使用適合shiro的Ehcache的CacheManager了。
2 配置Realm
修改Realm的bean,指定其cache相關屬性的值,如下:
<!-- Realm實現 --> <bean id="userRealm" class="com.huangzijian.realm.UserRealm"> <property name="cachingEnabled" value="true"/> <property name="authenticationCachingEnabled" value="true"/> <property name="authenticationCacheName" value="authenticationCache"/> <property name="authorizationCachingEnabled" value="true"/> <property name="authorizationCacheName" value="authorizationCache"/> </bean>
註意此處的cacheName,就是指在Ehcache中配置的cache,也就是通常在ehcache.xml中定義的cacahe。
3 配置securityManager
需要在securityManager中配置cacheManager屬性,引用配好的cacheManager,如下:
<!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager"> <property name="realms"> <list>
<ref bean="userRealm"/>
</list> </property> <property name="sessionManager" ref="sessionManager"/> <property name="cacheManager" ref="cacheManager"/> </bean>
經過上面三步,即可激活Shiro的Authentication和Authorization的緩存機制,從而不必要每次都讀取資料庫來確定該人員的角色之類的,極大的節省了資源。
九、總結
通過上述一步一步的進階,相信大家都可以實現自己想要的緩存了。本文是通過要實現shiro中的Authorization和Authentication緩存,來逐步讓大家接觸起緩存的使用。對於緩存的使用,還有很多更深入的內容,這裡只做了拋磚引玉,有待大家以後的使用瞭解了。