mirror of
https://github.com/LamGC/ContentGrabbingJi.git
synced 2025-04-30 06:37:36 +00:00
[Add] 增加新的缓存库类(HotDataCacheStore, StringRedisCacheStore);
[Add] CacheStore 增加update(String, T, long)方法, 该方法将以Unix时间戳设置过期时间; [Update] LocalHashCacheStore, RedisPoolCacheStore 适配CacheStore新方法; [Delete] 删除 RedisCacheStore 类;
This commit is contained in:
parent
8375b81b17
commit
a0efc3c0af
@ -4,6 +4,14 @@ import java.util.Date;
|
||||
|
||||
public interface CacheStore<T> {
|
||||
|
||||
/**
|
||||
* 更新或添加缓存项
|
||||
* @param key 缓存键名
|
||||
* @param value 缓存值
|
||||
* @param expire 有效期, 单位为ms(毫秒), 如不过期传入0或赋值
|
||||
*/
|
||||
void update(String key, T value, long expire);
|
||||
|
||||
/**
|
||||
* 更新或添加缓存项
|
||||
* @param key 缓存键名
|
||||
|
96
src/main/java/net/lamgc/cgj/bot/cache/HotDataCacheStore.java
vendored
Normal file
96
src/main/java/net/lamgc/cgj/bot/cache/HotDataCacheStore.java
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
package net.lamgc.cgj.bot.cache;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 具有继承性的热点数据缓存库
|
||||
* @param <T> 存储类型
|
||||
* @author LamGC
|
||||
*/
|
||||
public class HotDataCacheStore<T> implements CacheStore<T> {
|
||||
|
||||
private final CacheStore<T> parent;
|
||||
private final CacheStore<T> current;
|
||||
private final long expireTime;
|
||||
private final int expireFloatRange;
|
||||
private final Random random = new Random();
|
||||
private final Logger log = LoggerFactory.getLogger(HotDataCacheStore.class.getSimpleName() + "@" + Integer.toHexString(this.hashCode()));
|
||||
|
||||
/**
|
||||
* 构造热点缓存存储对象
|
||||
* @param parent 上级缓存存储库
|
||||
* @param current 热点缓存存储库, 最好使用本地缓存(例如 {@linkplain LocalHashCacheStore LocalHashCacheStore})
|
||||
* @param expireTime 本地缓存库的缓存项过期时间,
|
||||
* 该时间并不是所有缓存项的最终过期时间, 还需要根据expireFloatRange的设定随机设置, 公式:
|
||||
* {@code expireTime + new Random().nextInt(expireFloatRange)}
|
||||
* @param expireFloatRange 过期时间的浮动范围, 用于防止短时间内大量缓存项失效导致的缓存雪崩
|
||||
*/
|
||||
public HotDataCacheStore(CacheStore<T> parent, CacheStore<T> current, long expireTime, int expireFloatRange) {
|
||||
this.parent = parent;
|
||||
this.current = current;
|
||||
this.expireTime = expireTime;
|
||||
this.expireFloatRange = expireFloatRange;
|
||||
log.debug("HotDataCacheStore初始化完成. (Parent: {}, Current: {}, expireTime: {}, expireFloatRange: {})",
|
||||
parent, current, expireTime, expireFloatRange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String key, T value, long expire) {
|
||||
update(key, value, expire <= 0 ? null : new Date(System.currentTimeMillis() + expire));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String key, T value, Date expire) {
|
||||
parent.update(key, value, expire);
|
||||
current.update(key, value, expire);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getCache(String key) {
|
||||
if(!exists(key)) {
|
||||
log.debug("查询缓存键名不存在, 直接返回null.");
|
||||
return null;
|
||||
}
|
||||
T result = current.getCache(key);
|
||||
if(Objects.isNull(result)) {
|
||||
log.debug("Current缓存库未命中, 查询Parent缓存库");
|
||||
T parentResult = parent.getCache(key);
|
||||
if(Objects.isNull(parentResult)) {
|
||||
log.debug("Parent缓存库未命中, 缓存不存在");
|
||||
return null;
|
||||
}
|
||||
log.debug("Parent缓存命中, 正在更新Current缓存库...");
|
||||
current.update(key, parentResult, expireTime + random.nextInt(expireFloatRange));
|
||||
log.debug("Current缓存库更新完成.");
|
||||
result = parentResult;
|
||||
} else {
|
||||
log.debug("Current缓存库缓存命中.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String key) {
|
||||
return current.exists(key) || parent.exists(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String key, Date date) {
|
||||
return current.exists(key, date) || parent.exists(key, date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clear() {
|
||||
return current.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportedPersistence() {
|
||||
return current.supportedPersistence() || parent.supportedPersistence();
|
||||
}
|
||||
}
|
@ -28,6 +28,11 @@ public class LocalHashCacheStore<T> implements CacheStore<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String key, T value, long expire) {
|
||||
update(key, value, expire <= 0 ? null : new Date(System.currentTimeMillis() + expire));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String key, T value, Date expire) {
|
||||
if(cache.containsKey(key)) {
|
||||
|
@ -1,100 +0,0 @@
|
||||
package net.lamgc.cgj.bot.cache;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.Transaction;
|
||||
import redis.clients.jedis.exceptions.JedisConnectionException;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Date;
|
||||
|
||||
public abstract class RedisCacheStore<T> implements CacheStore<T> {
|
||||
|
||||
private final Jedis jedis;
|
||||
private final Logger log;
|
||||
private final String keyPrefix;
|
||||
|
||||
public RedisCacheStore(URI redisServerUri, String prefix) {
|
||||
this(redisServerUri, null, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个Redis缓存数据库对象
|
||||
* @param redisServerUri 数据库链接
|
||||
* @param password 登录密码(如果有)
|
||||
* @throws JedisConnectionException 当连接失败时抛出
|
||||
*/
|
||||
public RedisCacheStore(URI redisServerUri, String password, String prefix) throws JedisConnectionException {
|
||||
this.jedis = new Jedis(redisServerUri.getHost(), redisServerUri.getPort() <= 0 ? 6379 : redisServerUri.getPort());
|
||||
log = LoggerFactory.getLogger(this.getClass().getSimpleName() + "@" + Integer.toHexString(jedis.hashCode()));
|
||||
log.info("Redis数据库连接状态: {}", jedis.ping());
|
||||
if(password != null) {
|
||||
this.jedis.auth(password);
|
||||
}
|
||||
if(!Strings.isNullOrEmpty(prefix)) {
|
||||
keyPrefix = prefix.endsWith(".") ? prefix : prefix + ".";
|
||||
} else {
|
||||
keyPrefix = "";
|
||||
}
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
if(!"PONE".equals(jedis.ping())) {
|
||||
jedis.connect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String key, T value, Date expire) {
|
||||
Transaction multi = jedis.multi();
|
||||
multi.set(keyPrefix + key, parse(value));
|
||||
if(expire != null) {
|
||||
multi.expireAt(keyPrefix + key, expire.getTime());
|
||||
log.debug("已设置Key {} 的过期时间(Expire: {})", key, expire.getTime());
|
||||
}
|
||||
multi.exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getCache(String key) {
|
||||
return analysis(jedis.get(keyPrefix + key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String key) {
|
||||
return jedis.exists(keyPrefix + key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String key, Date date) {
|
||||
return exists(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clear() {
|
||||
String result = jedis.flushDB();
|
||||
log.info("flushDB返回结果: {}", result);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换方法
|
||||
* @param dataObj 原数据
|
||||
* @return 文本型数据
|
||||
*/
|
||||
protected abstract String parse(T dataObj);
|
||||
|
||||
/**
|
||||
* 将String数据转换成指定类型的对象
|
||||
* @param dataStr String数据
|
||||
* @return 泛型指定类型的对象
|
||||
*/
|
||||
protected abstract T analysis(String dataStr);
|
||||
|
||||
@Override
|
||||
public boolean supportedPersistence() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -21,15 +21,11 @@ public abstract class RedisPoolCacheStore<T> implements CacheStore<T> {
|
||||
}
|
||||
|
||||
public RedisPoolCacheStore(URI redisServerUri, JedisPoolConfig config, int timeout, String password, String prefix) {
|
||||
jedisPool = new JedisPool(config == null ? new GenericObjectPoolConfig<JedisPool>() : config, redisServerUri.getHost(),
|
||||
redisServerUri.getPort() <= 0 ? 6379 : redisServerUri.getPort(),
|
||||
timeout <= 0 ? Protocol.DEFAULT_TIMEOUT : timeout, password);
|
||||
log = LoggerFactory.getLogger(this.getClass().getSimpleName() + "@" + Integer.toHexString(jedisPool.hashCode()));
|
||||
if(prefix != null) {
|
||||
keyPrefix = prefix.endsWith(".") ? prefix : prefix + ".";
|
||||
} else {
|
||||
keyPrefix = "";
|
||||
}
|
||||
this(new JedisPool(config == null ? new GenericObjectPoolConfig<JedisPool>() : config, redisServerUri.getHost(),
|
||||
redisServerUri.getPort() == -1 ? 6379 : redisServerUri.getPort(),
|
||||
timeout <= 0 ? Protocol.DEFAULT_TIMEOUT : timeout, password),
|
||||
prefix
|
||||
);
|
||||
}
|
||||
|
||||
public RedisPoolCacheStore(JedisPool pool, String keyPrefix) {
|
||||
@ -45,16 +41,19 @@ public abstract class RedisPoolCacheStore<T> implements CacheStore<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String key, T value, long expire) {
|
||||
update(key, value, expire <= 0 ? null : new Date(System.currentTimeMillis() + expire));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String key, T value, Date expire) {
|
||||
Jedis jedis = jedisPool.getResource();
|
||||
Transaction multi = jedis.multi();
|
||||
multi.set(keyPrefix + key, parse(value));
|
||||
jedis.set(keyPrefix + key, parse(value));
|
||||
if(expire != null) {
|
||||
multi.expireAt(keyPrefix + key, expire.getTime());
|
||||
jedis.pexpireAt(keyPrefix + key, expire.getTime());
|
||||
log.debug("已设置Key {} 的过期时间(Expire: {})", key, expire.getTime());
|
||||
}
|
||||
multi.exec();
|
||||
jedis.close();
|
||||
}
|
||||
|
||||
@ -106,4 +105,14 @@ public abstract class RedisPoolCacheStore<T> implements CacheStore<T> {
|
||||
public boolean supportedPersistence() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换原本的分隔符(.)为(:).<br/>
|
||||
* 即将启用
|
||||
* @param key 要处理的键名
|
||||
* @return 处理后的键名
|
||||
*/
|
||||
public static String replaceKey(String key) {
|
||||
return key.replaceAll("\\.", ":");
|
||||
}
|
||||
}
|
||||
|
30
src/main/java/net/lamgc/cgj/bot/cache/StringRedisCacheStore.java
vendored
Normal file
30
src/main/java/net/lamgc/cgj/bot/cache/StringRedisCacheStore.java
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
package net.lamgc.cgj.bot.cache;
|
||||
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public class StringRedisCacheStore extends RedisPoolCacheStore<String> {
|
||||
public StringRedisCacheStore(URI redisServerUri, String prefix) {
|
||||
super(redisServerUri, prefix);
|
||||
}
|
||||
|
||||
public StringRedisCacheStore(URI redisServerUri, JedisPoolConfig config, int timeout, String password, String prefix) {
|
||||
super(redisServerUri, config, timeout, password, prefix);
|
||||
}
|
||||
|
||||
public StringRedisCacheStore(JedisPool pool, String keyPrefix) {
|
||||
super(pool, keyPrefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String parse(String dataObj) {
|
||||
return dataObj;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String analysis(String dataStr) {
|
||||
return dataStr;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user