Ehcache(二次封装,每个元素可自定义过期时间)

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

内置过期策略==ExpiryPolicyBuilder
no expiry:永不过期
time-to-live:固定持有时间(不会由于你访问而重新计算过期时间)- 类似session过期时间策略
time-to-idle:访问元素之后重新开始计算元素过期时间 - 类似redis的过期时间策略


官网文档: https://www.ehcache.org/documentation/3.10/cache-event-listeners.html

事件监听==EventType
EVICTED:
EXPIRED:keyValue键值对过期
REMOVED:删除keyValue键值对
CREATED:首次设置keyValue键值对
UPDATED:keyValue键值对的value值变更

代码

简单使用
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"));
    }    

}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值