public interface Cache {
T get(String key);
T hget(String key);
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 map);
void hset(String key, Map map, long expired);
void del(String key);
void hdel(String key);
void hdel(String key, String field);
}
@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;
}
}
/**
* 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 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 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 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 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 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 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 map) {
hset(key, map, default_expired);
}
@Override
public void hset(String key, Map 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 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 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;
}
}
/**
* @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";
}
}
/**
* @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";
}
}
/**
* @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 map = new HashMap<>();
map.put("name", "王弘博");
map.put("age", "18");
map.put("gender", "男");
cache.hset(key, map);
Map valueMap = cache.hget(key);
System.out.println("用户信息数据:" + valueMap);
cache.hdel(key);
Map valueMap1 = cache.hget(key);
System.out.println("用户信息数据:" + valueMap1);
return "ok";
}
}
测试完成,其实就是利用map的自带方法,来实现类似redis 的功能,思路是给大家了,具体代码由大家自由发挥吧。