Ehcache3.9+每个key指定不同时间

编程教程 (869) 2024-11-26 14:39:04

通过自定义ehcache缓存策略+自定义缓存事件来实现ehcahce中一个cache指定不同时间,且支持设定总缓存大小或数量。

引入依赖

<dependency>
      <groupId>org.ehcache</groupId>
      <artifactId>ehcache</artifactId>
      <version>3.9.1</version>
</dependency>

版本实测过3.9.1和3.10.x低版本没有widthService方法

指定缓存大小

 protected static final ResourcePools RESOURCE_POOLS = ResourcePoolsBuilder.newResourcePoolsBuilder()
 .heap(10, MemoryUnit.MB) 
 .offheap(20, MemoryUnit.MB) 
 .build();

注意:配置了offheap则所有value必须是实现了Serializable接口的对象否则报错

Seeing this exception and having no other serialization related issues is a red flag!

完整示例:

[user]

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.CacheRuntimeConfiguration;
import org.ehcache.config.ResourcePools;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheEventListenerConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;
import org.ehcache.event.CacheEvent;
import org.ehcache.event.CacheEventListener;
import org.ehcache.event.EventType;
import org.ehcache.expiry.ExpiryPolicy;

import java.io.Serializable;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

public class EhCacheProvider {
    protected static final CacheManager CACHE_MANAGER = CacheManagerBuilder.newCacheManagerBuilder().build(true);
    protected static final ResourcePools RESOURCE_POOLS = ResourcePoolsBuilder.newResourcePoolsBuilder()
            .heap(10, MemoryUnit.MB)
            .offheap(20, MemoryUnit.MB)
            .build();

    /**
     * access 缓存 会话参考
     */
    protected static final String TTL_CACHE_NAME = "TIME_TO_LIVE_CACHE_NAME";
    /**
     * 指定时间缓存
     */
    protected static final String TTI_CACHE_NAME = "TIME_TO_IDLE_DEFAULT_CACHE";


    /**
     * 获取缓存值
     * @param key 缓存key
     * @return 值
     */
    public static String getString(String key){
        return get(key,String.class);
    }

    public static Object get(String key){
        Object object = getCache(false).get(key);
        if (Objects.isNull(object)){
            object = getCache(true).get(key);
        }
        if (Objects.nonNull(object)){
            CacheData<Object> cacheData=(CacheData<Object>) object;
            return cacheData.getData();
        }
        return object;
    }

    /**
     * 获取缓存值 指定返回类型
     * @param key 缓存key
     * @return 值
     */
    public static <V> V get(String key,Class<V> type){
        Object result = get(key);
        return Optional.ofNullable(result)
                .map(elem -> Convert.convert(type, elem))
                .orElse(null);
    }

    /**
     *  设置缓存
     * @param key string
     * @param value 数据
     * @param expireMs 过期/毫秒
     * @param <K> k类型
     */
    public static <K extends Serializable> void set(String key, Object value, Long expireMs) {
        set(key, value, expireMs,false);
    }

    /**
     *  设置缓存
     * @param key string
     * @param value 数据
     * @param <K> k类型
     */
    public static <K extends Serializable> void set(String key, Object value) {
        set(key, value,null,false);
    }

    /**
     * 删除缓存
     */
    public static void remove(Serializable key) {
        getCache(false).remove(key);
        getCache(true).remove(key);
    }

    public static <K extends Serializable> boolean exists(K key){
        boolean containsKey = getCache(false).containsKey(key);
        if (!containsKey){
            containsKey = getCache(true).containsKey(key);
        }
        return containsKey;
    }

    /**
     *  设置缓存
     * @param key string
     * @param value 数据
     * @param expireMs 过期/毫秒
     * @param <K> k类型
     */
    public static <K extends Serializable> void set(K key, Object value, Long expireMs,boolean live) {
        if (Objects.isNull(value)){
            return;
        }

        Cache<? super Serializable, ? super Serializable> cache = getCache(live);

        //另外一个相同的key移除
        getCache(!live).remove(key);

        if (expireMs != null && expireMs >= 0) {
            CacheRuntimeConfiguration runtimeConfiguration = cache.getRuntimeConfiguration();
            CustomExpiryPolicy expiryPolicy = (CustomExpiryPolicy) runtimeConfiguration.getExpiryPolicy();
            expiryPolicy.setExpire(key, Duration.ofMillis(expireMs));
        }

        CacheData<Object> cacheData = new CacheData<>(value);
        cache.put(key, cacheData);
    }

    /**
     * 销毁全部容器
     */
    public static void close() {
        CACHE_MANAGER.close();
    }

    /**
     * 缓存数据封装
     * @param <T>
     */
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public static class CacheData<T> implements Serializable{
        T data;
    }


    /**
     * 获取tti cache
     * @return cache
     */
    public static Cache<? super Serializable, ? super Serializable> getCache(boolean live) {
        String cacheName=live?TTL_CACHE_NAME:TTI_CACHE_NAME;
        Cache<? super Serializable, ? super Serializable> cache = CACHE_MANAGER.getCache(cacheName,Serializable.class,Serializable.class);
        if(cache == null) {
            synchronized (EhCacheProvider.class) {
                cache = CACHE_MANAGER.getCache(cacheName,Serializable.class,Serializable.class);
                if(cache == null) {
                    //缓存过期策略
                    CustomExpiryPolicy<Serializable,Serializable> customExpiryPolicy;
                    if (live){
                        customExpiryPolicy = new CustomTTLExpiryPolicy<>();
                    }else{
                        customExpiryPolicy = new CustomTTIExpiryPolicy<>();
                    }

                    //事件监听
                    CacheEventListenerConfigurationBuilder cacheEventListenerConfiguration = CacheEventListenerConfigurationBuilder
                            .newEventListenerConfiguration(new CustomCacheEventListener<>(cacheName), EventType.CREATED, EventType.values())
                            .ordered().asynchronous();

                    return CACHE_MANAGER.createCache(cacheName, CacheConfigurationBuilder.newCacheConfigurationBuilder(
                                    Serializable.class,
                                    Serializable.class,
                                    RESOURCE_POOLS)
                            .withExpiry(customExpiryPolicy)
                            .withService(cacheEventListenerConfiguration));
                }else {
                    return cache;
                }
            }
        }else {
            return cache;
        }
    }


    /**
     * keyValue自定义过期时间策略
     * <p>
     *
     * @param <K>
     * @param <V>
     */
    private abstract 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);
        }
    }

    /**
     * time to live 策略 类session机制
     * @param <K>
     * @param <V>
     */
    private static class CustomTTLExpiryPolicy<K, V> extends CustomExpiryPolicy<K, V>{
        @Override
        public Duration getExpiryForAccess(K key, Supplier<? extends V> value) {
            return super.getExpiryForAccess(key, value);
        }
    }

    /**
     * time to idle 策略
     * @param <K>
     * @param <V>
     */
    private static class CustomTTIExpiryPolicy<K, V> extends CustomExpiryPolicy<K, V>{
        @Override
        public Duration getExpiryForAccess(K key, Supplier<? extends V> value) {
            return null;
        }
    }

    /**
     *  移除过期/积压/删除缓存
     *
     * @param <K> key类型
     * @param <V> 值类型
     */
    private static class CustomCacheEventListener<K, V> implements CacheEventListener<K, V> {

        String cacheName;

        Cache<Serializable,Serializable> cache;

        CustomExpiryPolicy customExpiryPolicy;


        public CustomCacheEventListener(String cacheName) {
            this.cacheName = cacheName;
        }


        @Override
        public void onEvent(CacheEvent<? extends K, ? extends V> 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());
            }
        }
    }



    public static void main(String[] args) {
        List<String> list = Arrays.asList("A", "B");
        CacheData<List<String>> listCacheData = new CacheData<>();
        listCacheData.setData(list);
        set("list",list,5*1000L);
        Object object = get("list");
        System.out.println(1);
    }
    public static void t1(){

        String key=  "key";
        String key2=  "key2";
        String key3="key3";
        String data= "data";
        String data2= "data2";
        set(key,data,3*1000L);
        set(key2,data2,5*1000L);
        set("key3",data2,7*1000L);
        while (Objects.nonNull(get(key2))){
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(get(key2));
        }
        System.out.println(exists(key));
        System.out.println(exists("key3"));
        System.out.println("缓存已过期");

        System.out.println(get(key));
        System.out.println(get(key2));
        System.out.println(get("key3"));

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

[/user]

 


评论
User Image
提示:请评论与当前内容相关的回复,广告、推广或无关内容将被删除。

相关文章
       Ehcache 3.6 配置缓存过期时间,上一次写Ehcache缓存是3.3.0版本,没想到3.6.X的时候3.3版本的方式也弃用了       3.3版本ehcache参考:  ...
通过自定义ehcache缓存策略+自定义缓存事件来实现ehcahce中一个cache指定不同时间,且支持设定总缓存大小或数量。引入依赖&lt;dependency&gtl;
java编程之Ehcache3.x 缓存过期时间Java配置demo
spring data redis设置缓存的过期时间,spring data redis更新缓存的过期时间
一、项目环境Spring Boot 2.1.2.RELEASEshiro-spring 1.4二、去掉URL jsessionid在shiro配置中,配置关闭url中显示sessionId ...
需求将静态资源如css/js/图片缓存到不用每次都到后端服务去拿取,减少性能消耗。 配置nginx缓存配置缓存文件存放信息在nginx配置文件,httpd内部配
mybatis事物访问数据库的一级缓存和二级缓存和刷新缓存
Java编程之spring boot shiro redis整合基于角色和权限的安全管理,Java编程,spring boot,shiro,权限控制
一、spring boot shiro 无状态token认证项目结构图​二、无状态spring boot shiro相关配置2.1shiro redis 缓存配置首先是实现shiro的cache...
通常使用普通的资源可以通过Cache-Control配置通知浏览器进行缓存,但是有些小站没有cdn资源,用了外站的cdn资源,速度一般又想提升用户体验,ServiceWorker缓存就有用武之地了。
spring boot 开发技巧,在开发web项目中跳过thyemeleaf模板/js/css等缓存避免每次修改资源文件都需要重启服务器
spring boot 2.x设置静态资源缓存时间
问题描述git 提交代码报错 :error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413导致原因1. 本...
项目设置清理策略进入harbor项目。 清理策略配置:保留7天拉取的镜像 规则生成说明:应用到仓库匹配**, 保留最近7天被拉取过的 artifacts基于条件