项目中使用的了redis的0号数据库,现在要求在客户端离线时给客户通知,离线的判断是时间大于某个值,解决方法使用redis的过期监听功能实现这个功能,但是0号数据库已经使用中,为了不监听过多的过期事件,启用1号数据库,下面就上代码:
application.yml配置,其中database1是我自定义的,用于判断是否启用1号数据库:
spring:
redis:
host: 127.0.0.1
port: 6379
password: foobared
database: 0
database1: true
jedis:
pool:
# 连接池中的最大空闲连接
max-idle: 50
# 连接池最大连接数(使用负值表示没有限制)
max-active: 500
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: 300
# 连接池中的最小空闲连接
min-idle: 5
#空闲对象逐出器线程的运行间隔时间.空闲连接线程释放周期时间
time-between-eviction-runs: 1000
普通redis配置:
package com.gnetek.monitor.redis.util;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* @Description RedisTemplate工具
* @Author Darren Huang
* @Date 2024-02-29 9:10
*/
public class RedisTemplateUtil {
/**
* 获取redis模板
*
* @param redisConnectionFactory Redis连接工厂
* @return {@link RedisTemplate}<{@link String}, {@link Object}>
*/
public static RedisTemplate<String, Object> getRedisTemplate (RedisConnectionFactory redisConnectionFactory) {
//创建redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
//创建json序列化工具
//GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jsonRedisSerializer.setObjectMapper(om);
//创建String序列化工具
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//设置key的序列化
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
//设置value的序列化
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
//设置默认序列化工具
redisTemplate.setDefaultSerializer(jsonRedisSerializer);
//设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
package com.gnetek.monitor.redis.config;
import com.gnetek.monitor.redis.util.RedisTemplateUtil;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
/**
* Redis配置类:Lettuce客户端
*
* @author Darren
* @date 2023/05/11
*/
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class LettuceRedisConfig {
@Bean(name = "redisTemplate")
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
return RedisTemplateUtil.getRedisTemplate(redisConnectionFactory);
}
}
用于过期监听的redis数据配置:
package com.gnetek.monitor.redis.config;
import cn.hutool.core.util.StrUtil;
import com.gnetek.monitor.redis.util.RedisTemplateUtil;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import java.time.Duration;
/**
* @Description 描述
* @Author Darren Huang
* @Date 2024-02-28 17:31
*/
@Configuration
@ConditionalOnProperty(name = "spring.redis.database1", havingValue = "true")
public class SessionRedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port:6379}")
private int port;
@Value("${spring.redis.password:#{null}}")
private String password;
@Bean(name = "sessionRedisTemplate")
public RedisTemplate<String, Object> sessionRedisTemplate() {
//连接池配置
GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
poolConfig.setMaxIdle(10);
poolConfig.setMaxTotal(100);
poolConfig.setMinIdle(2);
//redis客户端配置
LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder =
LettucePoolingClientConfiguration.builder().
commandTimeout(Duration.ofSeconds(60));
builder.poolConfig(poolConfig);
LettuceClientConfiguration lettuceClientConfiguration = builder.build();
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(host, port);
redisStandaloneConfiguration.setDatabase(1);
if (StrUtil.isNotBlank(password)) {
redisStandaloneConfiguration.setPassword(password);
}
LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration);
factory.afterPropertiesSet();
return RedisTemplateUtil.getRedisTemplate(factory);
}
}
redis工具及工具注入:
package com.gnetek.monitor.redis.util;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @Description Redis工具类
* @Author Darren Huang
* @Date 2023-05-11 9:55
*/
@Slf4j
//@Component
public class RedisUtil {
private RedisTemplate<String, Object> redisTemplate;
private StringRedisTemplate stringRedisTemplate;
public RedisUtil(RedisTemplate<String, Object> redisTemplate, StringRedisTemplate stringRedisTemplate) {
this.redisTemplate = redisTemplate;
this.stringRedisTemplate = stringRedisTemplate;
}
// =============================1-common============================
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
}
}
}
/**
* 删除缓存
*
* @param keys 可以传多个
*/
public void del(Collection<String> keys) {
redisTemplate.delete(keys);
}
// ============================2-String=============================
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 递增 适用场景: https://blog.youkuaiyun.com/y_y_y_k_k_k_k/article/details/79218254 高并发生成订单号,秒杀类的业务逻辑等。。
*
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ================================3-Map=================================
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
/**
* 借助管道,实现Hash模糊匹配读取
*
* @param keyPattern key模糊匹配
* @param excludeKeys 排除的列
* @return
*/
public Object hGetAllByPipe(String keyPattern, String ...excludeKeys){
Set<String> keys = stringRedisTemplate.keys(keyPattern);
keys.removeAll(Arrays.asList(excludeKeys));
List<?> list = redisTemplate.executePipelined(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
for (String key : keys) {
connection.hashCommands().hGetAll(key.getBytes());
}
return null;
}
});
ArrayList<String> strings = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
strings.add(JSONUtil.toJsonPrettyStr(list.get(i)));
}
return strings;
}
// ============================4-set=============================
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
log.error(key, e);
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
log.error(key, e);
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0)
expire(key, time);
return count;
} catch (Exception e) {
log.error(key, e);
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
log.error(key, e);
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
log.error(key, e);
return 0;
}
}
// ============================5-zset=============================
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> zSGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
log.error(key, e);
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean zSHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
log.error(key, e);
return false;
}
}
public Boolean zSSet(String key, Object value, double score) {
try {
return redisTemplate.opsForZSet().add(key, value, 2);
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long zSSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0)
expire(key, time);
return count;
} catch (Exception e) {
log.error(key, e);
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long zSGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
log.error(key, e);
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long zSetRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
log.error(key, e);
return 0;
}
}
// ===============================6-list=================================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始 0 是第一个元素
* @param end 结束 -1代表所有值
* @return
* @取出来的元素 总数 end-start+1
*/
public List<?> lget(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
log.error(key, e);
return null;
}
}
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始 0 是第一个元素
* @return
* @取出来的元素 总数 end-start+1
*/
public List<?> lget(String key, long start) {
try {
return redisTemplate.opsForList().range(key, start, -1);
} catch (Exception e) {
log.error(key, e);
return null;
}
}
/**
* 获取list缓存的内容
*
* @param key 关键
* @return {@link List}<{@link Object}>
*/
public List<?> lget(String key) {
try {
return redisTemplate.opsForList().range(key, 0, -1);
} catch (Exception e) {
log.error(key, e);
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lgetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
log.error(key, e);
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lgetItem(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
log.error(key, e);
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lsetItem(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lsetItem(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lset(String key, List<?> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value.toArray());
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lset(String key, List<?> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value.toArray());
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
log.error(key, e);
return 0;
}
}
/**
* 阻塞访问List,左弹出
*
* @param key 键
* @param time 等待时间
* @param timeUnit 时间粒度
* @return 弹出的数据
*/
public Object lLeftPop(String key,long time,TimeUnit timeUnit) {
try {
Object leftPop = redisTemplate.opsForList().leftPop(key, time, timeUnit);
return leftPop;
} catch (Exception e) {
log.error(key, e);
return 0;
}
}
/**
* List,左写入
*
* @param key 键
* @param value 值
* @return 弹出的数据
*/
public Boolean lLeftPush(String key,Object value) {
try {
redisTemplate.opsForList().leftPush(key, value);
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* List,右写入
*
* @param key 键
* @param value 值
* @return 弹出的数据
*/
public Boolean lRightPush(String key,Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
log.error(key, e);
return false;
}
}
/**
* 执行
*
* @param redisCallback 复述,回调
* @return {@link Object}
*/
public Object execute(RedisCallback<?> redisCallback){
return redisTemplate.execute(redisCallback);
}
/**
* 获取键
*
* @param s 年代
* @return {@link Set}<{@link String}>
*/
public Set<String> keys(String s) {
return redisTemplate.keys(s);
}
}
下面redis工具注入,这里注意,我另外写了一个sessionRedisUtil用于,对redis1号数据库的读写:
package com.gnetek.monitor.redis.config;
import com.gnetek.monitor.redis.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @Description Redis Component
* @Author Darren Huang
* @Date 2024-02-27 16:15
*/
@Component
public class RedisComponent {
@Resource(name = "redisTemplate")
private RedisTemplate<String, Object> redisTemplate;
@Autowired(required = false)
@Qualifier(value = "sessionRedisTemplate")
private RedisTemplate<String, Object> sessionRedisTemplate;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Bean(name = "redisUtil")
@ConditionalOnMissingBean(RedisUtil.class)
@ConditionalOnBean(RedisTemplate.class)
public RedisUtil redisUtil() {
return new RedisUtil(redisTemplate, stringRedisTemplate);
}
@Bean(name = "sessionRedisUtil")
@ConditionalOnProperty(name = "spring.redis.database1", havingValue = "true")
public RedisUtil sessionRedisUtil() {
return new RedisUtil(sessionRedisTemplate, stringRedisTemplate);
}
}
使用方法:
@Autowired
private RedisUtil redisUtil;
@Resource(name = "sessionRedisUtil")
private RedisUtil sessionRedisUtil;
redis过期监听:
public static final String EXPIRED_TOPIC = "__keyevent@1__:expired";
package com.gnetek.monitor.api.listener;
import com.gnetek.monitor.common.constants.CacheNames;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @Description redis 数据库1的 key 过期监听事件
* @Author Darren Huang
* @Date 2024-02-27 11:38
*/
@Slf4j
@Component
public class RedisKeyExpiredListener extends KeyExpirationEventMessageListener {
/**
* __keyevent@1__:expired
*/
private static final Topic KEYEVENT_1_EXPIRED_TOPIC = new PatternTopic(CacheNames.EXPIRED_TOPIC);
/**
* Creates new {@link MessageListener} for {@code __keyevent@*__:expired} messages.
*
* @param listenerContainer must not be {@literal null}.
*/
public RedisKeyExpiredListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
protected void doRegister(RedisMessageListenerContainer listenerContainer) {
listenerContainer.addMessageListener(this, KEYEVENT_1_EXPIRED_TOPIC);
}
@Override
public void onMessage(Message message, byte[] pattern) {
String expiredKey = new String(message.getBody());
log.error("过期key = {}", expiredKey);
// 在这里处理过期事件的逻辑
if (expiredKey.startsWith(CacheNames.EXPIRED_LISTENER_KEY)) {
// TODO: 2024/2/27 触发事件,发送邮件
}
}
}
项目使用Redis 0号数据库,需在客户端离线时通知,通过判断时间是否大于某个值确定离线。为避免监听过多过期事件,启用1号数据库实现过期监听功能。文中给出了application.yml配置、普通Redis配置、过期监听的Redis数据配置、Redis工具及注入等内容。
1807

被折叠的 条评论
为什么被折叠?



