开源框架编码技巧一(缓存设计篇)

文章介绍了Nacos中缓存的设计,包括Cache接口及其通用缓存项配置,展示了SimpleCache、AutoExpireCache(实现过期清理)、SynchronizedCache(线程安全)和LruCache(LRU缓存)四种不同的实现方式,以及如何通过CacheBuilder构建不同特性的缓存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、本地缓存设计

1、Nacos的缓存结构设计为例,通用缓存为例,支持不同模式的缓存,

支持更复杂功能,可以直接使用Guava和Caffine直接使用.

   ①、Cache缓存接口.

package com.alibaba.nacos.common.cache;

import java.util.concurrent.Callable;

/**
 * Cache method collection definition.
 * @author zzq
 * @date 2021/7/30
 */
public interface Cache<K, V> {

    /**
     * Cache a pair of key value. If the key value already exists, the value will be overwritten.
     * @param key cache key
     * @param val cache value
     */
    void put(K key, V val);
    
    /**
     * Take the corresponding value from the cache according to the cache key.
     * @param key cache key
     * @return cache value
     */
    V get(K key);
    
    /**
     * Get the value in the cache according to the primary key, and put it into the cache after processing by the function.
     * @param key cache key
     * @param call a function, the return value of the function will be updated to the cache
     * @return cache value
     * @throws Exception callable function interface throw exception
     */
    V get(K key, Callable<? extends V> call) throws Exception;
    
    /**
     * Take the corresponding value from the cache according to the cache key, and remove this record from the cache.
     * @param key cache key
     * @return cache value
     */
    V remove(K key);
    
    /**
     * Clear the entire cache.
     */
    void clear();
    
    /**
     * Returns the number of key-value pairs in the cache.
     * @return  number of key-value pairs
     */
    int getSize();
}

  CacheItemProperties【通用缓存项配置】

package com.alibaba.nacos.common.cache.builder;

/**
 * Cache item's own attributes.
 * @author zzq
 * @date 2021/7/30
 */
public class CacheItemProperties {
    
    private long expireNanos;
    
    public long getExpireNanos() {
        return expireNanos;
    }
    
    public void setExpireNanos(long expireNanos) {
        this.expireNanos = expireNanos;
    }
}

2、缓存实现

①、SimpleCache,不带任何功能.

package com.alibaba.nacos.common.cache.impl;

import com.alibaba.nacos.common.cache.Cache;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * Simple implementation of {@code Cache}.
 * @author zzq
 * @date 2021/7/30
 */
public class SimpleCache<K, V> implements Cache<K, V> {
    
    private Map<K, V> cache;
    
    public SimpleCache(int size) {
        cache = new HashMap(size);
    }
    
    @Override
    public void put(K key, V val) {
        cache.put(key, val);
    }
    
    @Override
    public V get(K key) {
        return cache.get(key);
    }
    
    @Override
    public V get(K key, Callable<? extends V> call) throws Exception {
        if (cache.containsKey(key)) {
            return cache.get(key);
        } else {
            V v2 = call.call();
            cache.put(key, v2);
            return v2;
        }
    }
    
    @Override
    public V remove(K key) {
        return cache.remove(key);
    }
    
    @Override
    public void clear() {
        cache.clear();
    }
    
    @Override
    public int getSize() {
        return cache.size();
    }
}

 AutoExpireCache,实现过期清理.

package com.alibaba.nacos.common.cache.decorators;

import com.alibaba.nacos.common.cache.Cache;
import com.alibaba.nacos.common.cache.builder.CacheItemProperties;

import java.util.HashMap;
import java.util.concurrent.Callable;

/**
 * A wrapper that automatically expires the cache.
 * @author zzq
 * @date 2021/7/30
 */
public class AutoExpireCache<K, V> implements Cache<K, V> {
    
    private long expireNanos;
    
    private Cache<K, V> delegate;
    
    private HashMap<K, CacheItemProperties> keyProp = new HashMap<>();
    
    public AutoExpireCache(Cache<K, V> delegate, long expireNanos) {
        this.expireNanos = expireNanos;
        this.delegate = delegate;
    }
    
    @Override
    public void put(K key, V val) {
        keyProp.put(key, cacheItemProperties());
        this.delegate.put(key, val);
    }
    
    @Override
    public V get(K key) {
        if (keyProp.get(key) != null && isExpire(keyProp.get(key))) {
            this.keyProp.remove(key);
            this.delegate.remove(key);
            return null;
        }
        return this.delegate.get(key);
    }

    @Override
    public V get(K key, Callable<? extends V> call) throws Exception {
        V cachedValue = this.get(key);
        if (null == cachedValue) {
            V v2 = call.call();
            this.put(key, v2);
            return v2;

        }
        return cachedValue;

    }
    
    @Override
    public V remove(K key) {
        keyProp.remove(key);
        return this.delegate.remove(key);
    }
    
    @Override
    public void clear() {
        keyProp.clear();
        this.delegate.clear();
    }
    
    @Override
    public int getSize() {
        return this.delegate.getSize();
    }
    
    private boolean isExpire(CacheItemProperties itemProperties) {
        return expireNanos != -1 && (System.nanoTime() - itemProperties.getExpireNanos() > expireNanos);
    }
    
    private CacheItemProperties cacheItemProperties() {
        CacheItemProperties cacheItemProperties = new CacheItemProperties();
        cacheItemProperties.setExpireNanos(System.nanoTime());
        return cacheItemProperties;
    }
}

SynchronizedCache,【线程安全的缓存】.

package com.alibaba.nacos.common.cache.decorators;

import com.alibaba.nacos.common.cache.Cache;

import java.util.concurrent.Callable;

/**
 * A wrapper that thread-safe cache.
 * @author zzq
 * @date 2021/7/30
 */
public class SynchronizedCache<K, V> implements Cache<K, V> {
    
    private final Cache<K, V> delegate;
    
    public SynchronizedCache(Cache<K, V> delegate) {
        this.delegate = delegate;
    }
    
    @Override
    public synchronized void put(K key, V val) {
        this.delegate.put(key, val);
    }
    
    @Override
    public synchronized V get(K key) {
        return this.delegate.get(key);
    }
    
    @Override
    public V get(K key, Callable<? extends V> call) throws Exception {
        return this.delegate.get(key, call);
    }
    
    @Override
    public synchronized V remove(K key) {
        return this.delegate.remove(key);
    }
    
    @Override
    public synchronized void clear() {
        this.delegate.clear();
    }
    
    @Override
    public synchronized int getSize() {
        return this.delegate.getSize();
    }
}

④、LruCache【LRU缓存】

package com.alibaba.nacos.common.cache.decorators;

import com.alibaba.nacos.common.cache.Cache;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * A wrapper that lru cache.
 * @author zzq
 * @date 2021/7/30
 */
public class LruCache<K, V> implements Cache<K, V> {
    
    private final Cache<K, V> delegate;
    
    private Map<K, V> keyMap;
    
    private K eldestKey;
    
    public LruCache(Cache<K, V> delegate, int size) {
        this.delegate = delegate;
        setSize(size);
    }
    
    @Override
    public int getSize() {
        return delegate.getSize();
    }
    
    public void setSize(final int size) {
        keyMap = new LinkedHashMap<K, V>(size, .75F, true) {
            private static final long serialVersionUID = 4267176411845948333L;
            
            @Override
            protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
                boolean tooBig = size() > size;
                if (tooBig) {
                    eldestKey = eldest.getKey();
                }
                return tooBig;
            }
          
        };
    }
    
    @Override
    public void put(K key, V val) {
        delegate.put(key, val);
        cycleKeyList(key);
    }
    
    @Override
    public V get(K key) {
        keyMap.get(key);
        return delegate.get(key);
    }
    
    @Override
    public V get(K key, Callable<? extends V> call) throws Exception {
        return this.delegate.get(key, call);
    }
    
    @Override
    public V remove(K key) {
        return delegate.remove(key);
    }
    
    @Override
    public void clear() {
        delegate.clear();
        keyMap.clear();
    }
    
    private void cycleKeyList(K key) {
        keyMap.put(key, null);
        if (eldestKey != null) {
            delegate.remove(eldestKey);
            eldestKey = null;
        }
    }
    
}

3、缓存建造器,选择不同缓存.

package com.alibaba.nacos.common.cache.builder;

import com.alibaba.nacos.common.cache.Cache;
import com.alibaba.nacos.common.cache.decorators.AutoExpireCache;
import com.alibaba.nacos.common.cache.decorators.LruCache;
import com.alibaba.nacos.common.cache.decorators.SynchronizedCache;
import com.alibaba.nacos.common.cache.impl.SimpleCache;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Cache builder.
 * @author zzq
 * @date 2021/7/30
 */
public class CacheBuilder<K, V> {
    
    private static final int DEFAULT_MAXIMUMSIZE = 1024;
    
    private static final int DEFAULT_INITIALIZE_CAPACITY = 1024;
    
    private static final int DEFAULT_EXPIRE_NANOS = -1;
    
    private long expireNanos = DEFAULT_EXPIRE_NANOS;
    
    private int maximumSize = DEFAULT_MAXIMUMSIZE;
    
    private int initializeCapacity = DEFAULT_INITIALIZE_CAPACITY;
    
    private boolean sync = false;
    
    private boolean lru = false;
    
    public static <K, V> CacheBuilder<K, V> builder() {
        return new CacheBuilder<>();
    }
    
    /**
     * Set expiration time.
     */
    public CacheBuilder<K, V> expireNanos(long duration, TimeUnit unit) {
        checkExpireNanos(duration, unit);
        this.expireNanos = unit.toNanos(duration);
        return this;
    }
    
    private void checkExpireNanos(long duration, TimeUnit unit) {
        if (duration < 0) {
            throw new IllegalArgumentException("duration cannot be negative");
        }
        if (Objects.isNull(unit)) {
            throw new IllegalArgumentException("unit cannot be null");
        }
    }
    
    /**
     * Set the maximum capacity of the cache pair.
     * @param maximumSize maximum capacity
     */
    public CacheBuilder<K, V> maximumSize(int maximumSize) {
        if (maximumSize < 0) {
            throw new IllegalArgumentException("size cannot be negative");
        }
        this.maximumSize = maximumSize;
        return this;
    }
    
    /**
     * Set whether the cache method is synchronized.
     * @param sync if sync value is true, each method of the constructed cache is synchronized.
     */
    public CacheBuilder<K, V> sync(boolean sync) {
        this.sync = sync;
        return this;
    }
    
    /**
     * Does the constructed cache support lru.
     * @param lru If the cache built for true is an lru cache.
     */
    public CacheBuilder<K, V> lru(boolean lru) {
        this.lru = lru;
        return this;
    }
    
    /**
     * Set the initial capacity of the cache pair.
     * @param initializeCapacity initialize capacity
     */
    public CacheBuilder<K, V> initializeCapacity(int initializeCapacity) {
        if (initializeCapacity < 0) {
            throw new IllegalArgumentException("initializeCapacity cannot be negative");
        }
        this.initializeCapacity = initializeCapacity;
        return this;
    }
    
    /**
     * Build the cache according to the builder attribute.
     */
    public Cache<K, V> build() {
        Cache<K, V> cache = new SimpleCache<>(initializeCapacity);
        if (lru) {
            cache = new LruCache<>(cache, maximumSize);
        }
        if (expireNanos != -1) {
            cache = new AutoExpireCache<>(cache, expireNanos);
        }
        if (sync) {
            cache = new SynchronizedCache<>(cache);
        }
        return cache;
    }
}
    private static final Cache<String, RateLimiter> CACHE;
    
    static {
        CACHE = CacheBuilder.<String, RateLimiter>builder()
                .expireNanos(1, TimeUnit.MINUTES)
                .initializeCapacity(CAPACITY_SIZE)
                .sync(true)
                .build();
    }

 具体使用

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大道之简

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值