一、Spring緩存概念
Spring從3.1開始定義了 org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 接口來統一不同的緩存技術; 并支援使用 JCache(JSR-107) 注解簡化我們開發。
常用的緩存實作有 RedisCache 、EhCache、ConcurrentMapCache 、Guava Cache(谷歌)等。
Spring Cache 介紹
Spring Cache是一個架構,實作了基于注解的緩存功能,隻需要簡單的加一個注解,就能實作緩存功能
Spring Cache提供了一層抽象,底層可以切換不同的Cache實作,具體是通過CacheManager接口來統一不同的緩存技術
針對于不同的緩存技術需要實作不同的CacheManager:
CacheManager | 描述 |
EhCacheCacheManager | 使用EhCache作為緩存技術 |
GuavaCacheManager | 使用Google的GuavaCache作為緩存技術 |
RedisCacheManager | 使用Redis作為緩存技術 |
Spring Cache 常用注解
我們來介紹Spring Cache用于緩存的常用的四個注解:
注解 | 說明 |
@EnableCaching | 開啟緩存注解功能 |
@Cacheable | 在方法執行前先檢視緩存中是否存有資料,如果有資料直接傳回資料;如果沒有,調用方法并将傳回值存入緩存 |
@CachePut | 将方法的傳回值放到緩存 |
@CacheEvict | 将一條或多條從緩存中删除 |
在Spring項目中,使用緩存技術隻需要導入相關緩存技術的依賴包,并在啟動類上加上@EnableCaching開啟緩存支援即可
二、Ehcache介紹
EhCache 是一個純Java的程序内緩存管理架構,屬于開源的Java分布式緩存架構,主要用于通用緩存,Java EE和輕量級容器,是從 Hibernate 的緩存開始的。
目前版本已到了Ehcache 3.10,Ehcache 3引入了以下内容:
- 改進的 API,利用 Java 泛型并簡化緩存互動,
- 與javax.cache API (JSR-107)完全相容,
- 堆下存儲功能,包括僅堆下緩存,
- 開箱即用的Spring Caching和Hibernate內建,這要歸功于javax.cache支援
1、 Ehcache特性:
1、快速輕量: Ehcache 是最快的 Java 緩存之一,很小的 jar 包
2、伸縮性:緩存在記憶體和磁盤存儲可以伸縮到數 G
3、靈活性:Ehcache 1.2 具備對象 API 接口和可序列化 API 接口。
4、标準支援 Ehcache 提供了對 JSR107 JCACHE API 最完整的實作
5、可擴充性 監聽器可以插件化
6、應用持久化 在 VM 重新開機後,持久化到磁盤的存儲可以複原資料
官網:Ehcache
2、 Ehcache 的加載子產品清單
ehcache-core:API,标準緩存引擎,RMI 複制和 Hibernate 支援
ehcache:分布式 Ehcache,包括 Ehcache 的核心和 Terracotta 的庫
ehcache-monitor:企業級監控和管理
ehcache-web:為 Java Servlet Container 提供緩存、gzip 壓縮支援的 filters
ehcache-jcache:JSR107 JCACHE 的實作
ehcache-jgroupsreplication:使用 JGroup 的複制
ehcache-jmsreplication:使用 JMS 的複制
ehcache-openjpa:OpenJPA 插件
ehcache-server:war 内部署或者單獨部署的 RESTful cache server
ehcache-unlockedreadsview:允許 Terracotta cache 的無鎖讀
ehcache-debugger:記錄 RMI 分布式調用事件
Ehcache for Ruby:Jruby and Rails 支援
3、核心定義:
- cache manager:緩存管理器,以前是隻允許單例的,不過現在也可以多執行個體了
- cache:緩存管理器内可以放置若幹 cache,存放資料的實質,所有 cache 都實作了 Ehcache 接口
- element:單條緩存資料的組成機關
- system of record(SOR):可以取到真實資料的元件,可以是真正的業務邏輯、外部接口調用、存放真實資料的資料庫等等,緩存就是從 SOR 中讀取或者寫入到 SOR 中去的
Ehcache 支援的資料存儲包括:
- 堆上存儲 - 利用 Java 的堆上 RAM 記憶體來存儲緩存條目。此層使用與 您的 Java 應用程式,所有這些應用程式都必須由 JVM 垃圾回收器掃描。您的 JVM 堆空間越多 利用,應用程式性能受垃圾回收暫停的影響就越大。這家商店是 速度極快,但通常是您最有限的存儲資源。
- 堆外存儲 - 大小僅受可用 RAM 的限制。 不受 Java 垃圾回收 (GC) 的限制。 非常快,但比堆上存儲慢,因為在存儲和重新通路資料時,必須将資料移入和移出 JVM 堆。
- 磁盤存儲 - 利用磁盤(檔案系統)存儲緩存條目。 這種類型的存儲資源通常非常豐富,但比基于 RAM 的存儲慢得多。至于所有使用磁盤的應用程式 存儲時,建議使用快速專用的磁盤來優化吞吐量。
- 群集存儲 - 此資料存儲是遠端伺服器上的緩存。 遠端伺服器可以選擇具有故障轉移伺服器,以提供改進的高可用性。 由于群集存儲會因網絡延遲以及建立用戶端/伺服器一緻性等因素而帶來性能損失, 從本質上講,此層比本地堆外存儲慢。
開發執行個體:
引入依賴:
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.0</version>
</dependency>
配置檔案:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" name="defaultCache">
<diskStore path="../temp/bojun/ehcache" />
<!-- 預設緩存配置. -->
<defaultCache maxEntriesLocalHeap="100" eternal="false" timeToIdleSeconds="1800" timeToLiveSeconds="3600"
overflowToDisk="false" maxEntriesLocalDisk="100000" />
<cache name="SystemAuthorizingRealm" maxEntriesLocalHeap="2000"
eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0"
overflowToDisk="false" statistics="true">
</cache>
<cache name="shiro-activeSessionCache" maxEntriesLocalHeap="2000"
eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="0"
overflowToDisk="false" statistics="true">
</cache>
<!-- 系統緩存 -->
<cache name="sysCache" maxEntriesLocalHeap="100" eternal="false" overflowToDisk="false"/>
<cache name="cmsCache" maxEntriesLocalHeap="3000" eternal="false" overflowToDisk="false"/>
<cache name="captchaCache" maxEntriesLocalHeap="3000" timeToLiveSeconds="300" eternal="false" overflowToDisk="false"/>
<!-- 使用者緩存 -->
<cache name="userCache" maxEntriesLocalHeap="100" eternal="false" overflowToDisk="false"/>
<!-- 工作流子產品緩存 -->
<cache name="actCache" maxEntriesLocalHeap="100" eternal="false" overflowToDisk="false"/>
<cache name="sys.config" maxEntriesLocalHeap="100" eternal="false" overflowToDisk="false"/>
<!-- 系統活動會話緩存 -->
<cache name="activeSessionsCache" maxEntriesLocalHeap="10000" overflowToDisk="false"
eternal="false" timeToLiveSeconds="0" timeToIdleSeconds="0"
diskPersistent="true" diskExpiryThreadIntervalSeconds="600"/>
</ehcache>
配置類代碼:
@ConditionalOnProperty(name = "spring.cache.type", havingValue = "ehcache")
@Configuration
@EnableCaching//标注啟動緩存.
public class CacheConfig {
/**
* @param ehCacheManagerFactoryBean
* @return
*/
@Bean
public EhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBean ehCacheManagerFactoryBean){
System.out.println("CacheConfiguration.ehCacheCacheManager()");
return new EhCacheCacheManager(ehCacheManagerFactoryBean.getObject());
}
/*
* 據shared與否的設定,
* Spring分别通過CacheManager.create()
* 或new CacheManager()方式來建立一個ehcache基地.
*/
@Bean
public EhCacheManagerFactoryBean ehCacheManagerFactoryBean(){
System.out.println("CacheConfiguration.ehCacheManagerFactoryBean()");
EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean ();
cacheManagerFactoryBean.setShared(true);
return cacheManagerFactoryBean;
}
}
工具類:
public class CacheUtils {
private static CacheManager cacheManager = SpringContextHolder.getBean(CacheManager.class);
private static final String SYS_CACHE = "sysCache";
/**
* 擷取SYS_CACHE緩存
*
* @param key
* @return
*/
public static Object get(String key) {
return get(SYS_CACHE, key);
}
/**
* 擷取SYS_CACHE緩存
*
* @param key
* @param defaultValue
* @return
*/
public static Object get(String key, Object defaultValue) {
Object value = get(key);
return value != null ? value : defaultValue;
}
/**
* 寫入SYS_CACHE緩存
*
* @param key
* @return
*/
public static void put(String key, Object value) {
put(SYS_CACHE, key, value);
}
/**
* 從SYS_CACHE緩存中移除
*
* @param key
* @return
*/
public static void remove(String key) {
remove(SYS_CACHE, key);
}
/**
* 擷取緩存
*
* @param cacheName
* @param key
* @return
*/
public static Object get(String cacheName, String key) {
if( getCache(cacheName).get(key) == null){
return null;
}else {
return getCache(cacheName).get(key).get();
}
}
/**
* 擷取緩存
*
* @param cacheName
* @param key
* @param defaultValue
* @return
*/
public static Object get(String cacheName, String key, Object defaultValue) {
Object value = get(cacheName, key);
return value != null ? value : defaultValue;
}
/**
* 寫入緩存
*
* @param cacheName
* @param key
* @param value
*/
public static void put(String cacheName, String key, Object value) {
getCache(cacheName).put(key, value);
}
/**
* 從緩存中移除
*
* @param cacheName
* @param key
*/
public static void remove(String cacheName, String key) {
getCache(cacheName).evict(key);
}
/**
* 獲得一個Cache,沒有則顯示日志。
*
* @param cacheName
* @return
*/
private static Cache getCache(String cacheName) {
Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
throw new RuntimeException("目前系統中沒有定義“" + cacheName + "”這個緩存。");
}
return cache;
}
}
測試代碼:
@Cacheable(key="'user_'+#id",value="userCache")
public User getUserById(String id){
return userDao.findById(id); }
這是一個cache架構,可以根據需要引入不同的cache實作方案
大家好,歡迎來到Doker品牌,歡迎點贊和評論,您的鼓勵是我們持續更新的動力!更多資料請前往Doker 多克