使用map实现一个redis缓存

使用map实现一个redis缓存

 定义一个cache接口

public interface Cache {

    <T> T get(String key);

    <T> T hget(String key);

    <T> T hget(String key, String field);

    void set(String key, Object value);

    void set(String key, Object value, long expired);

    void hset(String key, String field, Object value);

    void hset(String key, String field, Object value, long expired);

    void hset(String key, Map<String, Object> map);

    void hset(String key, Map<String, Object> map, long expired);

    void del(String key);

    void hdel(String key);

    void hdel(String key, String field);

}

定义一个缓存实体bean

@Data
public class CacheObject {

    private String key;
    private Object value;
    private long expired;

    public CacheObject(String key, Object value, long expired) {
        this.key = key;
        this.value = value;
        this.expired = expired;
    }
}

实现这个接口MapCache

/**
 * 1、用map实现简易redis的功能
 * 2、redis的过期策略有三种:
 *      (1)、定时删除:设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除
 *      (2)、惰性删除:key过期的时候不删除,每次从数据库获取key的时候去检查是否过期,若过期,则删除,返回null
 *      (3)、定期删除:每隔一段时间执行一次删除(在redis.conf配置文件设置hz,1s刷新的频率)过期key操作
 *      惰性删除为redis服务器内置策略
 *      定期删除可以通过:
 *      第一、配置redis.conf 的hz选项,默认为10 (即1秒执行10次,100ms一次,值越大说明刷新频率越快,最Redis性能损耗也越大)
 *      第二、配置redis.conf的maxmemory最大值,当已用内存超过maxmemory限定时,就会触发主动清理策略
 *
 *      我们这里也像redis一样,同时使用 惰性删除 和 定期删除
 */
@Component
public class MapCache implements Cache {

    /**
     * 默认初始容量
     */
    private static final int initialCapacity = 1024;

    /**
     * 用户过期时间是-1
     */
    private static final int default_expired = -1;

    /**
     * 缓存容器
     */
    private Map<String, CacheObject> cachePool;

    public MapCache(int initialCapacity) {
        cachePool = new ConcurrentHashMap<>(initialCapacity);
    }

    public MapCache() {
        this(initialCapacity);
    }

    /**
     * 定期删除
     */
    @PostConstruct
    public void init() {
        ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1);

        executorService.scheduleAtFixedRate(() -> {

            long current = System.currentTimeMillis() / 1000;

            if (!CollectionUtils.isEmpty(cachePool)) {
                cachePool.values().removeIf(value -> value.getExpired() < current);
            }

        }, 100, 60 * 1000, TimeUnit.MILLISECONDS);
    }


    @Override
    public <T> T get(String key) {
        if (StringUtils.isBlank(key)) {
            return null;
        }
        CacheObject cacheObject = cachePool.get(key);
        if (cacheObject == null) {
            return null;
        }
        long current = System.currentTimeMillis() / 1000;
        if (default_expired != cacheObject.getExpired() && current > cacheObject.getExpired()) {
            del(key);//惰性删除
            return null;
        }
        return (T) cacheObject.getValue();
    }

    @Override
    public <T> T hget(String key) {
        if (StringUtils.isBlank(key)) {
            return null;
        }
        CacheObject cacheObject = cachePool.get(key);
        if (cacheObject == null) {
            return null;
        }

        long current = System.currentTimeMillis() / 1000;
        if (default_expired != cacheObject.getExpired() && current > cacheObject.getExpired()) {
            hdel(key);//惰性删除
            return null;
        }

        return (T) cacheObject.getValue();
    }

    @Override
    public <T> T hget(String key, String field) {
        if (StringUtils.isAnyBlank(key, field)) {
            return null;
        }
        CacheObject cacheObject = cachePool.get(key);
        if (cacheObject == null) {
            return null;
        }
        long current = System.currentTimeMillis() / 1000;
        if (default_expired != cacheObject.getExpired() && current > cacheObject.getExpired()) {
            hdel(key);//惰性删除
            return null;
        }
        Map<String, Object> valueMap = (Map) cacheObject.getValue();
        return (T) valueMap.get(field);
    }

    @Override
    public void set(String key, Object value) {
        set(key, value, default_expired);
    }

    @Override
    public void set(String key, Object value, long expired) {
        if (StringUtils.isBlank(key) || value == null) {
            return;
        }
        expired = expired >= 0 ? System.currentTimeMillis() / 1000 + expired : default_expired;
        CacheObject cacheObject = new CacheObject(key, value, expired);
        cachePool.put(key, cacheObject);
    }

    @Override
    public void hset(String key, String field, Object value) {
        hset(key, field, value, default_expired);
    }

    @Override
    public void hset(String key, String field, Object value, long expired) {
        if (StringUtils.isAnyBlank(key, field)) {
            return;
        }

        Map<String, Object> valueMap = null;

        CacheObject cacheObject = cachePool.get(key);
        if (cacheObject == null) {
            valueMap = new HashMap<>();
            valueMap.put(field, value);
            cacheObject = new CacheObject(key, valueMap, expired);
            cachePool.put(key, cacheObject);
            return;
        }

        expired = expired >= 0 ? System.currentTimeMillis() / 1000 + expired : default_expired;

        valueMap = (Map) cacheObject.getValue();
        valueMap.put(field, value);
        cacheObject = new CacheObject(key, valueMap, expired);
        cachePool.put(key, cacheObject);
    }

    @Override
    public void hset(String key, Map<String, Object> map) {
        hset(key, map, default_expired);
    }

    @Override
    public void hset(String key, Map<String, Object> map, long expired) {
        if (StringUtils.isBlank(key) || CollectionUtils.isEmpty(map)) {
            return;
        }
        CacheObject cacheObject = cachePool.get(key);
        if (cacheObject == null) {
            cachePool.put(key, new CacheObject(key, map, expired));
            return;
        }
        Map<String, Object> valueMap = (Map) cacheObject.getValue();
        map.putAll(valueMap);
        cachePool.put(key, new CacheObject(key, map, expired));
    }

    @Override
    public void del(String key) {
        if (StringUtils.isBlank(key)) {
            return;
        }
        cachePool.remove(key);
    }

    @Override
    public void hdel(String key) {
        if (StringUtils.isBlank(key)) {
            return;
        }
        cachePool.remove(key);
    }

    @Override
    public void hdel(String key, String field) {
        if (StringUtils.isAnyBlank(key, field)) {
            return;
        }

        CacheObject cacheObject = cachePool.get(key);
        if (cacheObject == null) {
            return;
        }

        long current = System.currentTimeMillis() / 1000;
        if (default_expired != cacheObject.getExpired() && current > cacheObject.getExpired()) {
            hdel(key);//惰性删除
            return;
        }

        Map<String, Object> valueMap = (Map) cacheObject.getValue();
        valueMap.remove(field);
        cacheObject = new CacheObject(key, valueMap, cacheObject.getExpired());
        cachePool.put(key, cacheObject);
    }
}

代码里所需要的工具类

public class StringUtils {

    public static boolean isBlank(CharSequence cs) {
        int strLen;
        if (cs != null && (strLen = cs.length()) != 0) {
            for (int i = 0; i < strLen; ++i) {
                if (!Character.isWhitespace(cs.charAt(i))) {
                    return false;
                }
            }
            return true;
        }
        return true;
    }

    /**
     * 所有参数都为空
     *
     * @param css
     * @return
     */
    public static boolean isAnyBlank(CharSequence... css) {
        if (ArrayUtils.isEmpty(css)) {
            return true;
        }
        for (CharSequence cs : css) {
            if (isBlank(cs)) {
                return true;
            }
        }
        return false;
    }

}

下面开始测试:

Controller

/**
 * @Description TODO
 * @Date 2019/8/12 13:02
 * @Created by 王弘博
 */
@RestController
public class TestCacheController {

    @Resource
    private Cache cache;

    @RequestMapping("/cache")
    public String cache() {

        String key = "123";

        cache.set(key, "王弘博");
        String str = cache.get(key);
        System.out.println("str:" + str);

        cache.set(key, "王弘博", 100);
        String str1 = cache.get(key);
        System.out.println("str1:" + str1);

        cache.del(key);
        String str2 = cache.get(key);
        System.out.println("str2:" + str2);
        
        return "ok";
    }

}

 测试结果

Controller

/**
 * @Description TODO
 * @Date 2019/8/12 13:02
 * @Created by 王弘博
 */
@RestController
public class TestCacheController {

    @Resource
    private Cache cache;

    @RequestMapping("/cache")
    public String cache() {

        String key = "userInfo";

        cache.hset(key, "name", "王弘博");
        cache.hset(key, "age", "18");
        cache.hset(key, "gender", "男");
        System.out.println("姓名:" + cache.hget(key, "name"));
        System.out.println("年龄:" + cache.hget(key, "age"));
        System.out.println("性别:" + cache.hget(key, "gender"));

        cache.hdel(key, "gender");
        System.out.println("姓名:" + cache.hget(key, "name"));
        System.out.println("年龄:" + cache.hget(key, "age"));
        System.out.println("性别:" + cache.hget(key, "gender"));

        return "ok";
    }

}

 测试结果

 

Controller

/**
 * @Description TODO
 * @Date 2019/8/12 13:02
 * @Created by 王弘博
 */
@RestController
public class TestCacheController {

    @Resource
    private Cache cache;

    @RequestMapping("/cache")
    public String cache() {

        String key = "userInfo";

        Map<String, Object> map = new HashMap<>();
        map.put("name", "王弘博");
        map.put("age", "18");
        map.put("gender", "男");
        cache.hset(key, map);

        Map<String,Object> valueMap = cache.hget(key);
        System.out.println("用户信息数据:" + valueMap);

        cache.hdel(key);
        Map<String,Object> valueMap1 = cache.hget(key);
        System.out.println("用户信息数据:" + valueMap1);

        return "ok";
    }

}

测试结果 

 

测试完成,其实就是利用map的自带方法,来实现类似redis 的功能,思路是给大家了,具体代码由大家自由发挥吧。

发布了165 篇原创文章 · 获赞 103 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/qq_33101675/article/details/103386265