mirror of
				https://github.com/LamGC/ContentGrabbingJi.git
				synced 2025-11-04 02:26:57 +00:00 
			
		
		
		
	[Add] 增加新的缓存库类(HotDataCacheStore, StringRedisCacheStore);
[Add] CacheStore 增加update(String, T, long)方法, 该方法将以Unix时间戳设置过期时间; [Update] LocalHashCacheStore, RedisPoolCacheStore 适配CacheStore新方法; [Delete] 删除 RedisCacheStore 类;
This commit is contained in:
		@ -4,6 +4,14 @@ import java.util.Date;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
public interface CacheStore<T> {
 | 
					public interface CacheStore<T> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 更新或添加缓存项
 | 
				
			||||||
 | 
					     * @param key 缓存键名
 | 
				
			||||||
 | 
					     * @param value 缓存值
 | 
				
			||||||
 | 
					     * @param expire 有效期, 单位为ms(毫秒), 如不过期传入0或赋值
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void update(String key, T value, long expire);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 更新或添加缓存项
 | 
					     * 更新或添加缓存项
 | 
				
			||||||
     * @param key 缓存键名
 | 
					     * @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
 | 
					    @Override
 | 
				
			||||||
    public void update(String key, T value, Date expire) {
 | 
					    public void update(String key, T value, Date expire) {
 | 
				
			||||||
        if(cache.containsKey(key)) {
 | 
					        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) {
 | 
					    public RedisPoolCacheStore(URI redisServerUri, JedisPoolConfig config, int timeout, String password, String prefix) {
 | 
				
			||||||
        jedisPool = new JedisPool(config == null ? new GenericObjectPoolConfig<JedisPool>() : config, redisServerUri.getHost(),
 | 
					        this(new JedisPool(config == null ? new GenericObjectPoolConfig<JedisPool>() : config, redisServerUri.getHost(),
 | 
				
			||||||
                redisServerUri.getPort() <= 0 ? 6379 : redisServerUri.getPort(),
 | 
					                redisServerUri.getPort() == -1 ? 6379 : redisServerUri.getPort(),
 | 
				
			||||||
                timeout <= 0 ? Protocol.DEFAULT_TIMEOUT : timeout, password);
 | 
					                timeout <= 0 ? Protocol.DEFAULT_TIMEOUT : timeout, password),
 | 
				
			||||||
        log = LoggerFactory.getLogger(this.getClass().getSimpleName() + "@" + Integer.toHexString(jedisPool.hashCode()));
 | 
					                prefix
 | 
				
			||||||
        if(prefix != null) {
 | 
					        );
 | 
				
			||||||
            keyPrefix = prefix.endsWith(".") ? prefix : prefix + ".";
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            keyPrefix = "";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public RedisPoolCacheStore(JedisPool pool, String keyPrefix) {
 | 
					    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
 | 
					    @Override
 | 
				
			||||||
    public void update(String key, T value, Date expire) {
 | 
					    public void update(String key, T value, Date expire) {
 | 
				
			||||||
        Jedis jedis = jedisPool.getResource();
 | 
					        Jedis jedis = jedisPool.getResource();
 | 
				
			||||||
        Transaction multi = jedis.multi();
 | 
					        jedis.set(keyPrefix + key, parse(value));
 | 
				
			||||||
        multi.set(keyPrefix + key, parse(value));
 | 
					 | 
				
			||||||
        if(expire != null) {
 | 
					        if(expire != null) {
 | 
				
			||||||
            multi.expireAt(keyPrefix + key, expire.getTime());
 | 
					            jedis.pexpireAt(keyPrefix + key, expire.getTime());
 | 
				
			||||||
            log.debug("已设置Key {} 的过期时间(Expire: {})", key, expire.getTime());
 | 
					            log.debug("已设置Key {} 的过期时间(Expire: {})", key, expire.getTime());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        multi.exec();
 | 
					 | 
				
			||||||
        jedis.close();
 | 
					        jedis.close();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -106,4 +105,14 @@ public abstract class RedisPoolCacheStore<T> implements CacheStore<T> {
 | 
				
			|||||||
    public boolean supportedPersistence() {
 | 
					    public boolean supportedPersistence() {
 | 
				
			||||||
        return true;
 | 
					        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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user