Ehcache
官网: https://www.ehcache.org/
优势: 持续维护
作用: Java写的缓存工具
<!-- https://mvnrepository.com/artifact/org.ehcache/ehcache -->
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.1</version>
</dependency>
概念
官网文档: https://www.ehcache.org/documentation/3.10/expiry.html
官网文档: https://www.ehcache.org/documentation/3.10/cache-event-listeners.html
代码
简单使用
public class OtherTest {
@Test
public void test10() {
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("preConfigured",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(100))
.build())
.build(true);
//必须key、value的类型一致,否则也找不到,非常的严格
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(100)).build());
myCache.put(1L, "da one!");
String value = myCache.get(1L);
Console.log("=================");
Console.log(value);
Console.log("=================");
cacheManager.close();
}
}
工具封装
/**
* Java缓存(封装ehcache)
* 官网:https://www.ehcache.org/documentation/3.10/getting-started.html
*
* @author LinRuChang
* @version 1.0
* @date 2022/08/30
* @since 1.8
**/
public class EhcacheUtil {
protected static final CacheManager CACHE_MANAGER = CacheManagerBuilder.newCacheManagerBuilder().build(true);
/**
* 默认缓存容器名
*/
protected static final String DEFAULT_CACHE_NAME = "DEFAULT_CACHE";
static {
//默认缓存容器创建
createCacheIfNot(DEFAULT_CACHE_NAME);
}
public static Cache<? super Serializable, ? super Serializable> getCache(String cacheName) {
return CACHE_MANAGER.getCache(cacheName,Serializable.class,Serializable.class);
}
/**
* 线程安全的创建缓存容器
* @param cacheName 缓存容器名字
* @return
*/
public static Cache<? super Serializable, ? super Serializable> createCache(String cacheName) {
Assert.notBlank(cacheName, "缓存名缺失");
Cache<? super Serializable, ? super Serializable> cache = getCache(cacheName);
if(cache == null) {
synchronized (EhcacheUtil.class) {
cache = getCache(cacheName);
if(cache == null) {
//缓存过期策略
CustomExpiryPolicy<Object, Object> customExpiryPolicy = new CustomExpiryPolicy<>();
//事件监听
CacheEventListenerConfigurationBuilder cacheEventListenerConfiguration = CacheEventListenerConfigurationBuilder
.newEventListenerConfiguration(new CustomCacheEventListener(cacheName), EventType.CREATED, EventType.values())
.ordered().asynchronous();
return CACHE_MANAGER.createCache(cacheName, CacheConfigurationBuilder.newCacheConfigurationBuilder(
Serializable.class,
Serializable.class,
ResourcePoolsBuilder.heap(Long.MAX_VALUE))
.withExpiry(customExpiryPolicy)
.withService(cacheEventListenerConfiguration));
}else {
return cache;
}
}
}else {
return cache;
}
}
/**
* 如果不存在则创建缓存对象
*
* @param cacheName 缓存名
* @return 缓存对象
*/
public static Cache<? super Serializable, ? super Serializable> createCacheIfNot(String cacheName) {
Cache<? super Serializable, ? super Serializable> cache = getCache(cacheName);
return cache != null ? cache : createCache(cacheName);
}
/**
* 获取键值
*
* @param cacheName 缓存容器名 不设置默认使用{@link EhcacheUtil#DEFAULT_CACHE_NAME}
* @param key 键名
*/
public static <K extends Serializable> Serializable get(String cacheName, K key) {
if (key == null) {
return null;
}
cacheName = StrUtil.blankToDefault(cacheName, DEFAULT_CACHE_NAME);
return (Serializable) (createCacheIfNot(cacheName).get(key));
}
/**
* 获取键值 【从默认缓存容器中取{@link EhcacheUtil#DEFAULT_CACHE_NAME}】
*
* @param key 键名
*/
public static <K extends Serializable> Serializable get(K key) {
return get(DEFAULT_CACHE_NAME, key);
}
public static List<? extends Cache.Entry<? super Serializable, ? super Serializable>> getAllEntry(String cacheName) {
cacheName = StrUtil.blankToDefault(cacheName, DEFAULT_CACHE_NAME);
Cache<? super Serializable, ? super Serializable> cache = getCache(cacheName);
return CollUtil.newArrayList(cache);
}
public static List<? extends Cache.Entry<? super Serializable, ? super Serializable>> getAllEntry() {
return getAllEntry(DEFAULT_CACHE_NAME);
}
/**
* 获取容器{cacheName}所有键值
* @param cacheName
* @return
*/
public static List<? super Serializable> getAllValues(String cacheName) {
cacheName = StrUtil.blankToDefault(cacheName, DEFAULT_CACHE_NAME);
return getAllEntry(cacheName).stream()
.map(entry -> entry.getValue())
.collect(Collectors.toList());
}
/**
* 获取默认容器所有键值
* @return
*/
public static List<? super Serializable> getAllValues() {
return getAllValues(DEFAULT_CACHE_NAME);
}
/**
* 获取容器{cacheName}所有的键名
* @return
*/
public static List<? super Serializable> getAllKeys(String cacheName) {
cacheName = StrUtil.blankToDefault(cacheName, DEFAULT_CACHE_NAME);
return getAllEntry(cacheName).stream()
.map(entry -> entry.getKey())
.collect(Collectors.toList());
}
/**
* 获取默认容器所有的键名
* @return
*/
public static List<? super Serializable> getAllKeys() {
return getAllKeys(DEFAULT_CACHE_NAME);
}
/**
* 获取键值 【从默认缓存容器中取{@link EhcacheUtil#DEFAULT_CACHE_NAME}】
*
* @param key 键名
*/
public static <K extends Serializable, V> V getByType(K key, Class<V> resultType) {
Serializable result = get(DEFAULT_CACHE_NAME, key);
return Optional.ofNullable(result)
.map(elem -> Convert.convert(resultType, elem))
.orElse(null);
}
/**
* 获取键值 【从默认缓存容器中取{@link EhcacheUtil#DEFAULT_CACHE_NAME}】
*
* @param key 键名
*/
public static <K extends Serializable> String getStr(K key) {
return getByType(key, String.class);
}
/**
* 设置缓存
*
* @param cacheName 缓存容器名字,不设置默认使用{@link EhcacheUtil#DEFAULT_CACHE_NAME}
* @param key 键名
* @param value 键值
* @param expireMs 键值对过期时间(单位毫秒)- 不设置、或负数默认为永不过期
*/
public static <K extends Serializable, V extends Serializable> void set(String cacheName, K key, V value, Long expireMs) {
cacheName = StrUtil.blankToDefault(cacheName, DEFAULT_CACHE_NAME);
if (expireMs != null && expireMs >= 0) {
CacheRuntimeConfiguration runtimeConfiguration = createCacheIfNot(cacheName).getRuntimeConfiguration();
CustomExpiryPolicy expiryPolicy = (CustomExpiryPolicy) runtimeConfiguration.getExpiryPolicy();
expiryPolicy.setExpire(key, Duration.ofMillis(expireMs));
}
createCacheIfNot(cacheName).put(key, value);
}
/**
* 设置缓存(使用默认的缓存容器{@link EhcacheUtil#DEFAULT_CACHE_NAME)
*
* @param key 键名
* @param value 键值
* @param expireMs 键值对过期时间(单位毫秒)- 不设置、或负数默认为永不过期
*/
public static <K extends Serializable, V extends Serializable> void set(String key, V value, Long expireMs) {
set(DEFAULT_CACHE_NAME, key, value, expireMs);
}
/**
* 设置缓存(使用默认的缓存容器{@link EhcacheUtil#DEFAULT_CACHE_NAME),键值对永不过期
*
* @param key 键名
* @param value 键值
*/
public static <V extends Serializable> void set(String key, V value) {
set(key, value, null);
}
/**
* 删除某个容器的某个键值对
* @param cacheName 容器名
* @param key 键名
* @return
*/
public static Serializable del(String cacheName, Serializable key) {
cacheName = StrUtil.blankToDefault(cacheName,DEFAULT_CACHE_NAME);
Cache<? super Serializable, ? super Serializable> cache = getCache(cacheName);
return Optional.ofNullable((Serializable)cache.get(key))
.map(value -> {
cache.remove(key);
return value;
})
.orElse(null);
}
/**
* 删除某人容器的某个键值对
* @param key 键名
* @return
*/
public static Serializable del(Serializable key) {
return del(DEFAULT_CACHE_NAME,key);
}
/**
* 清空某个缓存容器的内容
* @param cacheName 缓存容器名
*/
public static void clear(String cacheName) {
Cache<? super Serializable, ? super Serializable> cache = getCache(cacheName);
if(cache != null) {
cache.clear();
}
}
/**
* 销毁全部容器
*/
public static void close() {
CACHE_MANAGER.close();
}
/**
* keyValue自定义过期时间
* <p>
* 参考的实现{@link ExpiryPolicyBuilder#noExpiration(),ExpiryPolicyBuilder#timeToLiveExpiration(Duration),ExpiryPolicyBuilder#timeToIdleExpiration(Duration)}
* 文档<a href="https://www.ehcache.org/documentation/3.10/expiry.html"></a>
*
* @param <K>
* @param <V>
*/
private static class CustomExpiryPolicy<K, V> implements ExpiryPolicy<K, V> {
private final ConcurrentHashMap<K, Duration> keyExpireMap = new ConcurrentHashMap();
public Duration setExpire(K key, Duration duration) {
return keyExpireMap.put(key, duration);
}
public Duration getExpireByKey(K key) {
return Optional.ofNullable(keyExpireMap.get(key))
.orElse(null);
}
public Duration removeExpire(K key) {
return keyExpireMap.remove(key);
}
@Override
public Duration getExpiryForCreation(K key, V value) {
return Optional.ofNullable(getExpireByKey(key))
.orElse(Duration.ofNanos(Long.MAX_VALUE));
}
@Override
public Duration getExpiryForAccess(K key, Supplier<? extends V> value) {
return getExpireByKey(key);
}
@Override
public Duration getExpiryForUpdate(K key, Supplier<? extends V> oldValue, V newValue) {
return getExpireByKey(key);
}
}
/**
* 自定义事件处理 == 当前主要是用于去除自定义键值对的Map过期时间东西,防止内存溢出
* <p>
* 文档<a href="https://www.ehcache.org/documentation/3.10/cache-event-listeners.html"></a>
*
* @param <K>
* @param <V>
*/
private static class CustomCacheEventListener<K, V> implements CacheEventListener<K, V> {
String cacheName;
Cache cache;
CustomExpiryPolicy customExpiryPolicy;
public CustomCacheEventListener(String cacheName) {
this.cacheName = cacheName;
}
@Override
public void onEvent(CacheEvent event) {
Console.log("事件触发:{}======{}========{}", cacheName, event.getType(), event.getKey());
this.cache = ObjectUtil.defaultIfNull(cache, CACHE_MANAGER.getCache(cacheName, Serializable.class, Serializable.class));
this.customExpiryPolicy = ObjectUtil.defaultIfNull(customExpiryPolicy, (CustomExpiryPolicy) this.cache.getRuntimeConfiguration().getExpiryPolicy());
if (StrUtil.equalsAnyIgnoreCase(event.getType().name(), EventType.EXPIRED.name(), EventType.EVICTED.name(), EventType.REMOVED.name())) {
customExpiryPolicy.removeExpire(event.getKey());
}
}
}
}
Demo测试
class EhcacheUtilTest {
@Test
void test1() {
Cache<? super Serializable, ? super Serializable> test = EhcacheUtil.createCacheIfNot("test");
test.put("name", "lrc");
Object name = test.get("name");
Console.log(name);
}
@Test
@SneakyThrows
void test2() {
EhcacheUtil.set("name", "lrc");
EhcacheUtil.set("year", 20, 1000L);
EhcacheUtil.set("sport", "篮球",2000L);
Console.log("\n========初始值========");
Console.log("name:{}",EhcacheUtil.get("name"));
Console.log("year:{}",EhcacheUtil.get("year"));
Console.log("sport:{}",EhcacheUtil.get("sport"));
Thread.sleep(1000);
Console.log("\n========休眠1s后========");
Console.log("name:{}",EhcacheUtil.get("name"));
Console.log("year:{}",EhcacheUtil.get("year"));
Console.log("sport:{}",EhcacheUtil.get("sport"));
Thread.sleep(2000);
Console.log("\n========休眠2s后========");
Console.log("name:{}",EhcacheUtil.get("name"));
Console.log("year:{}",EhcacheUtil.get("year"));
Console.log("sport:{}",EhcacheUtil.get("sport"));
}
@Test
@SneakyThrows
void test3() {
EhcacheUtil.set("testCacheContainer", "name", "lrc", 1000L);
EhcacheUtil.set("testCacheContainer", "year", "20", null);
Console.log("\n========初始值========");
Console.log("name:{}",EhcacheUtil.get("testCacheContainer","name"));
Console.log("year:{}",EhcacheUtil.get("testCacheContainer","year"));
Thread.sleep(1000);
Console.log("\n========休眠1s后========");
Console.log("name:{}",EhcacheUtil.get("testCacheContainer","name"));
Console.log("year:{}",EhcacheUtil.get("testCacheContainer","year"));
}
@Test
@SneakyThrows
void test4() {
EhcacheUtil.set("year", 18);
Console.log(EhcacheUtil.get("year"));
EhcacheUtil.set("year", 25);
Console.log(EhcacheUtil.get("year"));
}
}