本地缓存Caffeine扩展

在当前的软件开发中,缓存技术被广泛应用于提高数据访问速度和降低数据库压力,如本地缓存和redis分布式缓存。小义本想实现一个caffeine+redis的多级缓存组件,但没想到又双叒叕踩坑了,今天主要聊聊本地缓存和​caffeine。

本地缓存作为单机服务最先触及的缓存层,选择合适的方案对于提升应用性能和响应速度至关重要,其​主要的实现方式有以下几种:

Ehcache
Ehcache是一个纯Java的缓存库,易于使用,提供了丰富的缓存策略,如LRU(最近最少使用)、FIFO(先进先出)等。

Guava Cache
Guava是Google开发的Java核心库,其中的缓存模块简单易用,支持自定义缓存驱逐策略,如大小限制、时间限制等。

Caffeine
Caffeine相比Guava,它提供了更好的内存管理机制和更快的读写性能,可以看做是guava的增强版。

之所以选择caffeine,是因为Caffeine是为Java 8及以上版本设计的,它利用了Java 8的并发特性,提供了高性能的缓存实现,而且Caffeine采用了一种结合LRU、LFU优点的算法:W-TinyLFU,在性能上有明显的优越性,同时过期时间设置,很符合自己要实现的组件的功能要求。本以为可以高效实现技术方案了,一写代码哪哪都是bug。​

过期时间设置不灵活
caffeine默认只支持统一设置缓存时间,如下面代码:

public static final Cache<String, Object> caffeine = Caffeine.newBuilder()
        .expireAfter(new CaffeineExpiry())
        .initialCapacity(100)
            .maximumSize(1000)
            .build();

无法获取缓存项的过期时间
不能针对不同的key设置个性化的过期时间,那自然就无法查看缓存项的剩余过期时间。如果想实现像redis那样有ttl命令可以查看key剩余的过期时间,需要自行扩展。

针对上述问题,还好caffeine支持自定义缓存对象,同时利用expireAfter方法可以实现对缓存项的过期时间设置,代码实现方式大致如下:

缓存对象类,设置过期时间和创建时间属性。

@Data
public class CacheObject<T> {
    T data;
    long expire;
    long createDate;//创建时间
    public CacheObject(T data, long second, long createDate) {
        this.data = data;
        this.expire = TimeUnit.SECONDS.toNanos(second);
        this.createDate = createDate;
    }
}

自定义caffeine本地缓存,可实现不同key的过期时间设置。

@Component
public class MyCaffeineCache {

    private Cache<String, CacheObject> CAFFEINE;

    public static final long NOT_EXPIRED = Long.MAX_VALUE;

    @PostConstruct
    public void init() {
        CAFFEINE = Caffeine.newBuilder()
                .expireAfter(new Expiry<String, CacheObject<?>>() {
                    @Override
                    public long expireAfterCreate(@NonNull String s, @NonNull CacheObject<?> cacheObject, long l) {
                        return cacheObject.getExpire();
                    }

                    @Override
                    public long expireAfterUpdate(@NonNull String s, @NonNull CacheObject<?> cacheObject, long l, @NonNegative long l1) {
                        return l1;
                    }

                    @Override
                    public long expireAfterRead(@NonNull String s, @NonNull CacheObject<?> cacheObject, long l, @NonNegative long l1) {
                        return l1;
                    }
                })
                .initialCapacity(100)
                .maximumSize(1024)
                .build();
    }

    public <T> void set(String key, T value, long expire) {
        CacheObject<T> tCacheObject = new CacheObject<>(value, expire, System.currentTimeMillis());
        CAFFEINE.put(key, tCacheObject);
    }

    public <T> T get(String key) {
        CacheObject<?> ifPresent = CAFFEINE.getIfPresent(key);
        if (Objects.isNull(ifPresent)) {
            return null;
        }
        return (T) ifPresent.getData();
    }

    public void delete(String key) {
        CAFFEINE.invalidate(key);
    }

    /**
     * 获取key的剩余过期时间,单位秒
     * @param key
     * @return
     */
    public Long getTtl(String key) {
        CacheObject o = (CacheObject)CAFFEINE.getIfPresent(key);
        if (Objects.isNull(o)) {
            return null;
        }
        Long flat = ((o.getCreateDate() + o.getExpire()/1000000) - System.currentTimeMillis())/1000;
        return flat;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值