Ehcache是什么?
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider,是一个应用缓存,基于服务进程实现。
为什么要用Ehcache?
那有的人就有疑问了,这么多分布式缓存组件,为什么要用Ehcache?没错,说的也是对的,就拿Redis来说,确实好用、简单。但看官们有没有想一个问题,大量的访问量,Redis的负载也是飙升的,有的人就会说了,Redis单机十万的QPS担心这些干嘛,没错也是对的,但是要基于复杂度低的查询,另外,应用操作Redis连接的耗时、网络IO这些都有可能成为Redis的瓶颈(官网也提出了这一点),所以在一些业务场景(数据不经常变动的、高频查询的)可以在Redis上做一层二级缓存,减少Redis连接耗时、网络IO对吞吐量的影响。
为什么集成Ehcache-3.x?
用过Ehcache的伙伴应该知道,2.x和3.x,2.x是net.sf.ehcache,而3.x是org.ehcache,在Ehcache3.x中新增了支持堆外内存存储特性:
相对于2.x存入堆内,减少了GC触发,不影响业务代码中的对象heap空间。
实操
maven依赖
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.8.1</version>
</dependency>
工具类
public class EhCacheUtils {
/**
* EhCache管理实例,定义过期策略、资源池大小、预置缓存创建等。
*/
private static CacheManager cacheManager;
/**
* 是否开启EhCache缓存
*/
private static boolean ehcacheSwitch = EhCacheConstant.EHCACHE_SWITCH;
static {
ResourcePoolsBuilder resourcePoolsBuilder = ResourcePoolsBuilder.newResourcePoolsBuilder()
//不设置key个数,只设置大小
.offheap(EhCacheConstant.NON_HEAP_SIZE, MemoryUnit.MB);
//过期策略,有个存活时间设置
ExpiryPolicy expiryPolicy = ExpiryPolicyBuilder
.timeToLiveExpiration(Duration.ofMinutes(EhCacheConstant.NON_HEAP_LIVE_EXPIRY));
//指定的key和value的类型序列化
CacheConfiguration config = CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class, resourcePoolsBuilder)
//指定过期策略
.withExpiry(expiryPolicy)
.build();
CacheManagerBuilder cacheManagerBuilder = CacheManagerBuilder.newCacheManagerBuilder()
//自定义预置缓存,目前只存在一个缓存桶,使用key进行区分
.withCache(EhCacheConstant.PRE_CACHE_NAME, config);
cacheManager = cacheManagerBuilder.build();
//初始化
cacheManager.init();
}
/**
* 创建新EhCache缓存
*
* @param cacheName 缓存名(唯一)
* @param nonHeapSize 堆外内存大小限制, 单位: MB
* @param nonHeapLiveExpiry 存活时间限制,单位:Min/分钟, 创建后一段时间过期
* @return
*/
public static Cache createCache(String cacheName, long nonHeapSize, long nonHeapLiveExpiry) {
Cache cache = getCache(cacheName);
if (cache == null) {
cache = cacheManager.createCache(cacheName, CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
//不设置个数,只设置大小
.offheap(nonHeapSize, MemoryUnit.MB))
.withExpiry(ExpiryPolicyBuilder
.timeToLiveExpiration(Duration.ofMinutes(nonHeapLiveExpiry))).build());
}
return cache;
}
/**
* 移除EhCache缓存
*
* @param cacheName 缓存名(唯一)
*/
public static void removeCache(String cacheName) {
cacheManager.removeCache(cacheName);
}
/**
* 获取缓存桶信息
*
* @param cacheName 缓存桶名称(唯一)
* @return
*/
private static Cache getCache(String cacheName) {
Cache<String, String> cache = cacheManager.getCache(cacheName, String.class, String.class);
if (cache == null) {
log.error("Get cache fail, Fail cache name: {}", cacheName);
return null;
}
return cache;
}
/**
* 存储数据,指定缓存桶、key、值
*
* @param cacheName 缓存桶名称(唯一)
* @param key 缓存key(唯一)
* @param value 缓存值
*/
public static void put(String cacheName, String key, String value) {
if (!ehcacheSwitch) {
return;
}
Cache cache = getCache(cacheName);
if (cache != null && !cache.containsKey(key)) {
cache.put(key, value);
}
}
/**
* 获取数据,指定缓存桶、key
*
* @param cacheName 缓存桶名称(唯一)
* @param key 缓存key(唯一)
*/
public static String get(String cacheName, String key) {
if (!ehcacheSwitch) {
return null;
}
Cache cache = getCache(cacheName);
if (cache != null && cache.containsKey(key)) {
return (String) cache.get(key);
}
return null;
}
/**
* 移除数据,指定缓存桶、key
*
* @param cacheName 缓存桶名称(唯一)
* @param key 缓存key(唯一)
*/
public static void remove(String cacheName, String key) {
if (!ehcacheSwitch) {
return;
}
Cache cache = getCache(cacheName);
if (cache != null && cache.containsKey(key)) {
cache.remove(key);
}
}
/**
* 批量移除数据,指定缓存桶、key,如果想删除所有,强烈使用cleanCache方法
*
* @param cacheName 缓存桶名称(唯一)
* @param keys 缓存key(集合)
*/
public static void removeBatch(String cacheName, Set<String> keys) {
if (!ehcacheSwitch) {
return;
}
Cache cache = getCache(cacheName);
if (cache != null) {
cache.removeAll(keys);
}
}
/**
* 清楚缓存同所有数据,指定缓存桶
*
* @param cacheName 缓存桶名称(唯一)
*/
public static void cleanCache(String cacheName) {
if (!ehcacheSwitch) {
return;
}
Cache cache = getCache(cacheName);
if (cache != null) {
cache.clear();
}
}
多业务可以对桶(cacheName)进行划分,你可以理解桶对应Redis的索引库。对Ehcache的缓存同步,可以使用redis发布订阅或者MQ都可以通知删除key即可。
总结:
总的来说使用了Ehcache对接口提升效果显而易见的,减少Redis连接、网络IO,主要就是快,当然还是有缺点的,虽然Ehcache支持分布式,如果真的要使用Ehcache实现分布式缓存,这将是一个极大的工作量,还是老老实实用第三方组件吧。
码字不易~讲解不易!!!点个赞再走。记住,我还是那个会撩头发的程序猿!!!