闲来无事,琢磨了一下,如果需要用到缓存,但是又刚好在没网络, 本地仓库又没有对应依赖的情况下,要怎么办。
这种情况下,就只能手动定义一个集合或Map,将要缓存的数据保存在里面。
但是会有不支持过期时间的问题。
所以就考虑了一下如何自定义一个缓存的工具类,可以实现类似单机版Redis的功能。
首先该类需要有保存数据和获取数据两个供用户使用的方法。
我的定义如下:
/**
* 向缓存中保存数据
* @param key
* @param value
*/
public void set(String key, Object value);
/**
* 向缓存中保存数据
* @param key
* @param value
* @param expire 数据有效期(过期时间)
*/
public void set(String key, Object value, long expire);
/**
* 从缓存中获取数据
* @param key
*/
public Object get(String key);
接下来是定义缓存的数据结构
这里我使用ConcurrentHashMap来保存数据,来应对并发情况。
该Map中的value项我定义为了CacheEntry. 这个类主要保存了该数据的值和过期时间。
class CacheEntry {
private long expireTime;
private Object value;
}
接下来是该类的完整代码:
@Component
public class LocalCache implements Serializable {
/**
* 缓存容器
*/
private Map<String, CacheEntry> container = new ConcurrentHashMap<>();
@Builder
@Data
static class CacheEntry {
private long expireTime;
private Object value;
}
/**
* 向缓存中保存数据
* @param key
* @param value
*/
public void set(String key, Object value) {
// 默认设置为永不过期,0代表永不过期
CacheEntry cacheNode = CacheEntry.builder()
.expireTime(0)
.value(value)
.build();
// 将数据保存到容器中
container.put(key, cacheNode);
}
/**
* 向缓存中保存数据,包含过期时间
* @param key
* @param value
* @param expire 数据有效期(过期时间)
*/
public void set(String key, Object value, long expire) {
// 先根据参数,计算出过期的时间戳
long expireTime = System.currentTimeMillis() + expire;
// 将计算出的过期时间保存到CacheEntry中, 便于在取值的时候判断是否过期
CacheEntry cacheEntry = CacheEntry.builder()
.expireTime(expireTime)
.value(value)
.build();
// 将数据保存到容器中
container.put(key, cacheNode);
}
/**
* 从缓存中获取数据
* @param key
*/
public Object get(String key) {
// 先获取数据
CacheEntry cacheNode = container.get(key);
// 如果为null,说明不存在
if (cacheNode == null) {
return null;
}
// 获取过期时间
long expireTime = cacheNode.getExpireTime();
// 如果没有设置过期时间 或者 没有到达过期时间, 则返回该数据
if (expireTime == 0L || expireTime >= System.currentTimeMillis()) {
return cacheNode.value;
}
// 其他情况下,说明该数据已过期,将该数据移除, 并返回null
container.remove(key);
return null;
}
}
这里在类上使用了@Component注解,将该类注入到Spring容器中,可以直接通过@Autowired使用。
如果要在Springboot启动时,向缓存中保存数据,只需要将启动类 implements CommandLineRunner, 重写run方法即可。
@SpringBootApplication
public class LocalCacheApplication implements CommandLineRunner {
@Autowired
private LocalCache localCache;
public static void main(String[] args) {
SpringApplication.run(LocalCacheApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
localCache.set("test", "testValue");
System.out.println(localCache.get("test"));
}
}