Skip to content

SivanCache的固定缓存大小实现

Sivan_Xin edited this page Dec 11, 2023 · 4 revisions

代码实现

定义SivanCache接口,实现put方法

	@Override
    @SivanCacheInterceptor(aof = true, evict = true)
    public V put(K key, V value) {
        //1.1 尝试驱除
        SivanCacheEvictContext<K,V> context = new SivanCacheEvictContext<>();
        context.key(key).size(sizeLimit).cache(this);

        ISivanCacheEntry<K,V> evictEntry = evict.evict(context);

        // 添加拦截器调用
        if(ObjectUtil.isNotNull(evictEntry)) {
            // 执行淘汰监听器
            ISivanCacheRemoveListenerContext<K,V> removeListenerContext = SivanCacheRemoveListenerContext.<K,V>newInstance().key(evictEntry.key())
                    .value(evictEntry.value())
                    .type(SivanCacheRemoveType.EVICT.code());
            for(ISivanCacheRemoveListener<K,V> listener : context.cache().removeListeners()) {
                listener.listen(removeListenerContext);
            }
        }

        //2. 判断驱除后的信息
        if(isSizeLimit()) {
            throw new SivanCacheRuntimeException("当前队列已满,数据添加失败!");
        }

        //3. 执行添加
        return map.put(key, value);
    }

淘汰策略

先实现一个简单的缓存淘汰策略

package com.xin.cache.support.evict;

import com.xin.cache.api.ISivanCache;
import com.xin.cache.api.ISivanCacheEvictContext;
import com.xin.cache.model.SivanCacheEntry;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 丢弃策略-先进先出
 * @author sivan
 *  
 */
public class SivanCacheEvictFifo<K,V> extends AbstractSivanCacheEvict<K,V> {

    /**
     * queue 信息
     *  
     */
    private final Queue<K> queue = new LinkedList<>();

    @Override
    public SivanCacheEntry<K,V> doEvict(ISivanCacheEvictContext<K, V> context) {
        SivanCacheEntry<K,V> result = null;

        final ISivanCache<K,V> cache = context.cache();
        // 超过限制,执行移除
        if(cache.size() >= context.size()) {
            K evictKey = queue.remove();
            // 移除最开始的元素
            V evictValue = cache.remove(evictKey);
            result = new SivanCacheEntry<>(evictKey, evictValue);
        }

        // 将新加的元素放入队尾
        final K key = context.key();
        queue.add(key);

        return result;
    }

}

缓存引导类

package com.xin.cache.bs;

import com.github.houbb.heaven.util.common.ArgUtil;
import com.xin.cache.api.*;
import com.xin.cache.core.SivanCache;
import com.xin.cache.support.evict.SivanCacheEvicts;
import com.xin.cache.support.listener.remove.SivanCacheRemoveListeners;
import com.xin.cache.support.listener.slow.SivanCacheSlowListeners;
import com.xin.cache.support.load.SivanCacheLoads;
import com.xin.cache.support.persist.SivanCachePersists;
import com.xin.cache.support.proxy.SivanCacheProxy;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 缓存引导类
 * @author sivan
 *  
 */
public final class SivanCacheBs<K,V> {

    private SivanCacheBs(){}

    /**
     * 创建对象实例
     * @param <K> key
     * @param <V> value
     * @return this
     *  
     */
    public static <K,V> SivanCacheBs<K,V> newInstance() {
        return new SivanCacheBs<>();
    }

    /**
     * map 实现
     *  
     */
    private Map<K,V> map = new HashMap<>();

    /**
     * 大小限制
     *  
     */
    private int size = Integer.MAX_VALUE;

    /**
     * 驱除策略
     *  
     */
    private ISivanCacheEvict<K,V> evict = SivanCacheEvicts.fifo();

    /**
     * 删除监听类
     *  
     */
    private final List<ISivanCacheRemoveListener<K,V>> removeListeners = SivanCacheRemoveListeners.defaults();

    /**
     * 慢操作监听类
     *  
     */
    private final List<ISivanCacheSlowListener> slowListeners = SivanCacheSlowListeners.none();

    /**
     * 加载策略
     *  
     */
    private ISivanCacheLoad<K,V> load = SivanCacheLoads.none();

    /**
     * 持久化实现策略
     *  
     */
    private ISivanCachePersist<K,V> persist = SivanCachePersists.none();

    /**
     * map 实现
     * @param map map
     * @return this
     *  
     */
    public SivanCacheBs<K, V> map(Map<K, V> map) {
        ArgUtil.notNull(map, "map");

        this.map = map;
        return this;
    }

    /**
     * 设置 size 信息
     * @param size size
     * @return this
     *  
     */
    public SivanCacheBs<K, V> size(int size) {
        ArgUtil.notNegative(size, "size");

        this.size = size;
        return this;
    }

    /**
     * 设置驱除策略
     * @param evict 驱除策略
     * @return this
     *  
     */
    public SivanCacheBs<K, V> evict(ISivanCacheEvict<K, V> evict) {
        ArgUtil.notNull(evict, "evict");

        this.evict = evict;
        return this;
    }

    /**
     * 设置加载
     * @param load 加载
     * @return this
     *  
     */
    public SivanCacheBs<K, V> load(ISivanCacheLoad<K, V> load) {
        ArgUtil.notNull(load, "load");

        this.load = load;
        return this;
    }

    /**
     * 添加删除监听器
     * @param removeListener 监听器
     * @return this
     *  
     */
    public SivanCacheBs<K, V> addRemoveListener(ISivanCacheRemoveListener<K,V> removeListener) {
        ArgUtil.notNull(removeListener, "removeListener");

        this.removeListeners.add(removeListener);
        return this;
    }

    /**
     * 添加慢日志监听器
     * @param slowListener 监听器
     * @return this
     *  
     */
    public SivanCacheBs<K, V> addSlowListener(ISivanCacheSlowListener slowListener) {
        ArgUtil.notNull(slowListener, "slowListener");

        this.slowListeners.add(slowListener);
        return this;
    }

    /**
     * 设置持久化策略
     * @param persist 持久化
     * @return this
     *  
     */
    public SivanCacheBs<K, V> persist(ISivanCachePersist<K, V> persist) {
        this.persist = persist;
        return this;
    }

    /**
     * 构建缓存信息
     * @return 缓存信息
     *  
     */
    public ISivanCache<K,V> build() {
        SivanCache<K,V> cache = new SivanCache<>();
        cache.map(map);
        cache.evict(evict);
        cache.sizeLimit(size);
        cache.removeListeners(removeListeners);
        cache.load(load);
        cache.persist(persist);
        cache.slowListeners(slowListeners);

        // 初始化
        cache.init();
        return SivanCacheProxy.getProxy(cache);
    }

}

编写测试类

    /**
     * 大小指定测试
     *  
     */
    @Test
    public void helloTest() {
        ISivanCache<String, String> cache = SivanCacheBs.<String,String>newInstance()
                .size(2)
                .build();

        cache.put("1", "1");
        cache.put("2", "2");
        cache.put("3", "3");
        cache.put("4", "4");

        Assert.assertEquals(2, cache.size());
        System.out.println(cache.keySet());
    }