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));
    }

此时查询配置信息的方法就很简单了,和上面图片改造的相似,代码看起来也简洁许多。

相关文章
相关标签/搜索