年關将近,手中的活不是很多,應該是職業病,感覺手閑不下來,想到之前項目中存在的問題,正好有時間一一探索,研究下。
之前項目中用的是ehcache 2.x 版本,與springmvc內建,當時由于是個大型的cdn項目,其中有很大一部配置設定置資訊要快速到達。架構給的建議是要用本地緩存,畢竟網絡緩存可能會存在一些未知問題,這也不排除是我們網絡太次給我們造成了心裡壓力的原因。
使用ehcache2.x 的時候也是在網上搜尋很多示例,儲存到磁盤中,如果服務部署或者當機等導緻tomcat 挂掉後,重新開機緩存依舊存在,由于配置服務端接口采用的是詢問機制,如果不是新的将不會在下發配置資料。是以儲存和讀取成功則顯得非常重要。
ehcache2.x 的相關配置這裡就不貼了,咱們直接看ehcache3.x 的使用方式。
其中 ehcache3.x 改觀還是比較大的其中:
api的簡化,java泛型和使用上的互動
off-head 的使用,以及性能上的優化
其他的版本特性直接去官網看吧 http://www.ehcache.org/resources/
廢話不多說,直接上代碼!
第一部分 單獨測試ehcache3.x 的使用
根據 官網文檔 http://www.ehcache.org/documentation/3.4/getting-started.html
ehcache 3.x 建構緩存控制器的方式推薦使用 cacheMangerBuilder 這種方式
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("preConfigured",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)))
.build();
// 其中 CacheManagerBuilder.newCacheManagerBuilder().build(true) == cacheManager.init()
cacheManager.init();
Cache<Long, String> preConfigured =
cacheManager.getCache("preConfigured", Long.class, String.class);
Cache<Long, String> myCache = cacheManager.createCache("myCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)));
myCache.put(1L, "da one!");
String value = myCache.get(1L);
cacheManager.removeCache("preConfigured");
cacheManager.close();
磁盤緩存 可以用
PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.with(CacheManagerBuilder.persistence(new File(getStoragePath(), "myData")))
.withCache("threeTieredCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(10, EntryUnit.ENTRIES)
.offheap(1, MemoryUnit.MB)
.disk(20, MemoryUnit.MB, true)
)
).build(true);
Cache<Long, String> threeTieredCache = persistentCacheManager.getCache("threeTieredCache", Long.class, String.class);
threeTieredCache.put(1L, "stillAvailableAfterRestart");
persistentCacheManager.close();
這裡 persistentCacheManager 接口 繼承了 CacheManager 接口 ,而EhcacheManager 是persistentCacheManager 的
實作類 是以 也可以直接聲明建構的緩存控制器類型為EhcacheManager
上面是兩種方式的基本使用,下面貼出來一些設定
// 緩存的事件監聽
CacheEventListenerConfigurationBuilder cacheEventListenerConfiguration = CacheEventListenerConfigurationBuilder
// CacheEventListenerConfiguration使用建構器建立一個訓示偵聽器和要接收的事件(在這種情況下,建立和更新事件)
.newEventListenerConfiguration(new CacheLogListener(), EventType.CREATED, EventType.UPDATED)
// 可選地訓示傳遞模式 - 預設值是異步的和無序的(出于性能原因)
.unordered().asynchronous();
在使用過程中使用監聽器
ListenerObject listener = new ListenerObject();
cache.getRuntimeConfiguration().registerCacheEventListener(listener, EventOrdering.ORDERED,
EventFiring.ASYNCHRONOUS, EnumSet.of(EventType.CREATED, EventType.REMOVED));
// 登出在使用過程中注入的監聽器
cache.getRuntimeConfiguration().deregisterCacheEventListener(listener);
//設定緩存鍵值過期時間
CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(100))
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(20, TimeUnit.SECONDS)))
.build();
//調整可用于傳遞事件的并發級别
CacheConfiguration<Long, String> cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(5L))
.withDispatcherConcurrency(10) // 指出所需的并發級别
.withEventListenersThreadPool("listeners-pool").build();
Cache<Long, String> writeBehindCache = cacheManager.createCache("writeBehindCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10))
// 配置CacheLoaderWriter
.withLoaderWriter(new SampleLoaderWriter<Long, String>(singletonMap(41L, "zero")))
.add(WriteBehindConfigurationBuilder
// 我們将批量配置為3或最大寫入延遲為1秒
.newBatchedWriteBehindConfiguration(1, TimeUnit.SECONDS, 3)
.queueSize(3) // 我們還設定了後寫隊列的最大大小
.concurrencyLevel(1) // 定義後寫隊列的并發級别。這表明有多少個寫線程并行工作以異步更新記錄的底層系統。
.enableCoalescing()) // 啟用寫入合并行為,這可確定每個批次的每個鍵隻有一個更新到達記錄的底層系統。
.build());
線程池的使用:
// CacheManager cacheManager
// = CacheManagerBuilder.newCacheManagerBuilder()
// .using(PooledExecutionServiceConfigurationBuilder.newPooledExecutionServiceConfigurationBuilder()
// .defaultPool("dflt", 0, 10)
// .pool("defaultDiskPool", 1, 3)
// .pool("cache2Pool", 2, 2)
// .build())
// .with(new CacheManagerPersistenceConfiguration(new File(getStoragePath(), "myData")))
// .withDefaultDiskStoreThreadPool("defaultDiskPool")
// .withCache("cache1",
// CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
// ResourcePoolsBuilder.newResourcePoolsBuilder()
// .heap(10, EntryUnit.ENTRIES)
// .disk(10L, MemoryUnit.MB)))
// .withCache("cache2",
// CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
// ResourcePoolsBuilder.newResourcePoolsBuilder()
// .heap(10, EntryUnit.ENTRIES)
// .disk(10L, MemoryUnit.MB))
// .withDiskStoreThreadPool("cache2Pool", 2)) // 告訴緩存為其磁盤存儲使用特定的線程池。
// .build(true);
//
// Cache<Long, String> cache1 =
// cacheManager.getCache("cache1", Long.class, String.class);
// Cache<Long, String> cache2 =
// cacheManager.getCache("cache2", Long.class, String.class);
//
// cacheManager.close();
上面的特性基本貼完了,接下來給出最終代碼
private static String CACHE_NAME = "totalCache";
public static void main(String[] args) throws CachePersistenceException, MalformedURLException {
// 緩存的時間監聽
CacheEventListenerConfigurationBuilder cacheEventListenerConfiguration = CacheEventListenerConfigurationBuilder
// CacheEventListenerConfiguration使用建構器建立一個訓示偵聽器和要接收的事件(在這種情況下,建立和更新事件)
.newEventListenerConfiguration(new CacheLogListener(), EventType.CREATED, EventType.UPDATED)
// 可選地訓示傳遞模式 - 預設值是異步的和無序的(出于性能原因)
.unordered().asynchronous();
PersistentCacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.with(CacheManagerBuilder.persistence(new File(getStoragePath(), "myData")))
.using(PooledExecutionServiceConfigurationBuilder.newPooledExecutionServiceConfigurationBuilder()
.pool("defaultEventPool", 1, 3)
.pool("cache2Pool", 2, 2)
.build())
.withDefaultEventListenersThreadPool("defaultEventPool")
.withCache("cache1",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES))
.add(CacheEventListenerConfigurationBuilder
.newEventListenerConfiguration(new CacheLogListener(), EventType.CREATED, EventType.UPDATED))
.withDispatcherConcurrency(10) // 指出所需的并發級别
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(20, TimeUnit.SECONDS)))) // 設定過期時間
.withCache(CACHE_NAME,
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(10, EntryUnit.ENTRIES)
.offheap(1, MemoryUnit.MB)
.disk(20, MemoryUnit.MB, true))
.add(cacheEventListenerConfiguration)
.withDispatcherConcurrency(10) // 指出所需的并發級别
.withDiskStoreThreadPool("cache2Pool", 2)
).build(true);
Cache<Long, String> threeTieredCache =cacheManager.getCache(CACHE_NAME, Long.class, String.class);
// threeTieredCache.put(1L, "stillAvailableAfterRestart");
System.out.println("args = [" + threeTieredCache.get(1L) + "]");
cacheManager.close();
}
這裡沒有涉及叢集,序列化,和spring 內建等特性