java實現帶過時時間的緩存

緩存在咱們開發中十分常見,許多框架提供了緩存機制,若是咱們本身須要實現一個緩存,該怎麼實現呢?java

如今有個需求:咱們有個配置信息,只有一份,這個信息咱們存儲到redis中:鍵的名稱爲config,值爲json字符串,好比:redis

{
    "time":10,
    "type":1,
    "threshold":1000
}

       假如咱們對這個config裏面的內容使用十分頻繁,可是這個配置信息更改卻不怎麼頻繁,而且這個更改不必定要實時生效,那麼咱們能夠不用每次使用這個配置信息的時候都去查詢redis,由於對redis的性能會有所影響。咱們考慮到在應用層使用緩存,將配置信息在應用層緩存起來,每隔一分鐘自動清空一下緩存,清空緩存以後,下次請求就會訪問redis,獲取最新的配置信息。固然這之間配置信息可能已經更改,更改以後到應用最近一次從redis獲取數據有一個時間間距,這段時間所使用的配置信息可能不是最新的,固然咱們能夠忍受這一點。編程

注意本次博文咱們想緩存一個對象,而不是不少數據。json

一:簡單實現


1,首先咱們假如已經有了一個查詢配置信息的方法:緩存

 public MyConfig getConfig(){ return JSONObject.parseObject(stringRedisTemplate.opsForValue().get("config"), MyConfig.class); }

上面代碼只是演示,部分代碼在博文中沒有貼出。框架

  • MyConfig類內容和上面的json字符串對應。
  • get("config")中的config是redis中的鍵。

當程序調用上面的getConfig方法,每次都會從redis獲取數據,如今咱們對代碼進行改造。函數式編程

2,新建一個緩存類ConfigCache:函數

public final class ConfigCache {

    private static MyConfig myConfig = null;

    private ConfigCache() {
    }

    static {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        executor.scheduleAtFixedRate(() -> {
            myConfig = null;
        }, 0, 60, TimeUnit.SECONDS);
    }

    public static MyConfig get() {
        return myConfig;
    }

    public static void put(MyConfig newConfig) {
        myConfig = newConfig;
    }
}

咱們定義了一個緩存類,持有一個要緩存的對象MyConfig,提供獲取和設置方法。而且在每隔60秒清空一次該MyConfig對象,這就實現了緩存對象過時時間的功能。性能

3,從新編寫查詢配置信息的代碼:優化

    public MyConfig getConfig(){
        MyConfig myConfig = ConfigCache.get();
        if(myConfig == null){
            myConfig = JSONObject.parseObject(stringRedisTemplate.opsForValue().get("config"), MyConfig.class);
            ConfigCache.put(myConfig);
        }
        return myConfig;
    }

先查詢本地緩存,若是本地緩存爲空,則從redis查詢,而且保存至本地緩存;若是本地緩存不爲空,則直接使用本地緩存。

到此上面的簡單需求咱們就實現了。

二:借用java8 computeIfAbsent 方法優化代碼


image

上面圖片來自《Java 8函數式編程》一書。

很顯然1.3節的內容和圖片上面的5-31節代碼相似,java8提供了computeIfAbsent 方法簡化開發。咱們能夠提供本身的computeIfAbsent 方法,而後優化代碼。

1,改造緩存類ConfigCache

public final class ConfigCache {

    private static MyConfig myConfig = null;

    private ConfigCache() {
    }

    static {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        executor.scheduleAtFixedRate(() -> {
            myConfig = null;
        }, 0, 60, TimeUnit.SECONDS);
    }

    public static MyConfig computeIfAbsent(Supplier<MyConfig> supplier) {
        if (myConfig == null) {
            myConfig = supplier.get();
        }
        return myConfig;
    }
}

咱們刪除了get和put方法,新增了computeIfAbsent 方法,該方法須要一個Supplier,它提供一個MyConfig對象。

computeIfAbsent 代碼主要邏輯是若是myConifg不爲空,則返回該對象,不然經過Supplier構造一個對象給ConfigCache類的靜態屬性賦值,並返回該對象。

2,從新編寫查詢配置信息的實現的代碼:

    public MyConfig getConfig(){
        return ConfigCache.computeIfAbsent(JSONObject.parseObject(stringRedisTemplate.opsForValue().get("config"), MyConfig.class));
    }

此時查詢配置信息的方法就很簡單了,和上面圖片改造的相似,代碼看起來也簡潔許多。

相關文章
相關標籤/搜索