springboot+redis监听过期Key实践

 更新时间:2026年07月10日 14:42:41   作者:毅大师  
想知道如何用Redis轻松处理订单超时自动取消?本文教你利用Redis键过期通知机制,无需复杂代码即可监控订单有效期,通过配置Redis的keyspace notifications,结合Spring Boot,你能实时捕获过期Key并自动执行状态更新,立即掌握这一高效技巧,提升业务稳定性

前言

在订单业务中,有时候需要对订单设置有效期,有效期到了后如果还未支付,就需要修改订单状态。对于这种业务的实现,有多种不同的办法,比如:

1、使用Quartz,每次生成一个订单,就创建一个定时任务,到期后执行业务代码;

2、rabbitMq中的延迟队列;

3、对Redis的Key进行监控;

 1、引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

2、修改boot的redis配置

spring:
  #redis
  redis:
    database: 0
    host: 127.0.0.1
    password: redis_123456
    port: 6379

3、在服务器中

修改redis.conf配置文件(原来notify-keyspace-events 属性是" " 空的,我们只需要填上“Ex”就行了)

notify-keyspace-events "Ex"

4、创建一个Redis监控类

用于监控过期的key,该类需继承KeyExpirationEventMessageListener

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import java.nio.charset.StandardCharsets;

/**
 * @program: SpringCloud
 * @description: redis Key过期监听
 * @author: zhang yi
 * @create: 2020-03-24 14:14
 */
public class KeyExpiredListener extends KeyExpirationEventMessageListener {

    public KeyExpiredListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        System.out.println("过期key:" + message.toString());
    }
}

5、创建Redis配置类

import com.zy.rabbitmq.base.Listener.KeyExpiredListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

/**
 * @program: SpringCloud
 * @description: redis配置类
 * @author: zhang yi
 * @create: 2020-03-24 14:17
 */
@Configuration
public class RedisConfiguration {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
        redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
        return redisMessageListenerContainer;
    }

    @Bean
    public KeyExpiredListener keyExpiredListener() {
        return new KeyExpiredListener(this.redisMessageListenerContainer());
    }

}

6、这里提供一个redis工具类

用于存储值,获取值,获取过期时间等操作。

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
/**
 * redis 工具类
 * @Author ZhangYi
 */
@Component
public class RedisUtil {

	@Resource
	private RedisTemplate<String, Object> redisTemplate;

	/**
	 * 指定缓存失效时间
	 * 
	 * @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) {
			e.printStackTrace();
			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) {
			e.printStackTrace();
			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(CollectionUtils.arrayToList(key));
			}
		}
	}

	// ============================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) {
			e.printStackTrace();
			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) {
			e.printStackTrace();
			return false;
		}
	}
}

7、测试

(这里开放两个接口,一个set值,并设置过期时间为10秒,一个获取值和过期时间,当到达过期时间,看是否回去到过期Key)

    @GetMapping("/put")
    public String demo(){
        redisUtil.set("name","zhangyi",10);
        return "aaa";
    }

    @GetMapping("/get")
    public Map<String,Object> get(){
        Map<String,Object> m =new HashMap<>();
        m.put("time",redisUtil.getExpire("name"));
        m.put("val",redisUtil.get("name"));
        return m;
    }

成功获取到了过期Key,这里乱码是因为boot集成的Redis存key或者value的时候,没有配置字符串序列化。没有配置的话是默认使用jdk本身的序列化的。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java四舍五入时保留指定小数位数的五种方式

    Java四舍五入时保留指定小数位数的五种方式

    这篇文章主要介绍了Java四舍五入时保留指定小数位数的五种方式,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下
    2020-09-09
  • Spring Boot自定义错误视图的方法详解

    Spring Boot自定义错误视图的方法详解

    这篇文章主要介绍了Spring Boot自定义错误视图的方法详解,需要的朋友可以参考下
    2020-08-08
  • 在Web项目中手机短信验证码实现的全过程记录

    在Web项目中手机短信验证码实现的全过程记录

    这篇文章主要给大家介绍了关于在Web项目中实现短信验证码的全过程记录,文中通过示例代码介绍的非常详细,在文末跟大家提供了源码下载,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2017-12-12
  • java 单播、广播、组播详解及实例代码

    java 单播、广播、组播详解及实例代码

    这篇文章主要介绍了java 单播、广播、组播详解及实例代码的相关资料,需要的朋友可以参考下
    2017-02-02
  • Java进阶教程之String类

    Java进阶教程之String类

    这篇文章主要介绍了Java进阶教程之String类,String类对象是不可变对象(immutable object),String类是唯一一个不需要new关键字来创建对象的类,需要的朋友可以参考下
    2014-09-09
  • 线程池中使用spring aop事务增强

    线程池中使用spring aop事务增强

    这篇文章主要介绍了线程池中使用spring aop事务增强,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Spring Boot自定义Banner实现代码

    Spring Boot自定义Banner实现代码

    这篇文章主要介绍了Spring Boot自定义Banner实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • idea如何开启菜单栏

    idea如何开启菜单栏

    文章介绍了如何通过修改IntelliJ IDEA的样式文件`ui.lnf.xml`来重新显示被关闭的菜单栏,并分享了解决问题的步骤
    2025-01-01
  • Java业务校验工具实现方法

    Java业务校验工具实现方法

    这篇文章主要介绍了Java业务校验工具实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • springboot上传文件,url直接访问资源问题

    springboot上传文件,url直接访问资源问题

    这篇文章主要介绍了springboot上传文件,url直接访问资源问题。具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11

最新评论