Spring Boot实现动态定时任务

动态定时任务

项目基于Spring Boot 2.3.x。

项目需求有一个功能,可以添加多个定时触发一次的任务,并且这个触发时间在运行过程中(触发前)是更改的,于是想到使用动态定时任务。

目前想到的方法:

  • 任务写入数据库,定时轮询
    • 定时轮询,消耗资源,并且实时性不强
  • 使用RabbitMQ的TTL队列
    • 消息推入队列后只能等待消费,无法更改,如果修改了任务的触发时间,需要推入一条新消息,并且旧消息依旧存在
  • Redis keyspace notifications

Redis keyspace notifications

原理:使用Redis中的Redis keyspace notifications,去订阅一个Key过期的事件,在更改任务触发事件时,只需更改Key的过期时间。

spring-boot-starter-data-redis中有对应的实现。

  1. 配置RedisConfig
    @Configuration
    public class RedisConfig{
      
      // 其他配置
      
      /**
       * Reids消息监听器容器
       */
      @Bean
      public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory) {
          RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
          redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
          return redisMessageListenerContainer;
      }
    }
    
  2. 创建事件监听器
    @Component
    public class RedisKeyExpirationEventMessageListener extends KeyExpirationEventMessageListener {
      /**
       * @Component修饰的Bean使用构造函数构造对象时会自动注入构造函数的参数
       *
       * @param listenerContainer
       */
      public RedisKeyExpirationEventMessageListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
      }
      
      /**
       * 消息过期时处理
       * message只会返回Key,而不会返回值
       * 根据业务可以在设置时拼装Key,在处理时进行拆分
       *
       * @param message 过期消息
       */
      @Override
      protected void doHandleMessage(Message message) {
          String key = message.toString();
          // TODO
      }
    }
    

点进KeyspaceEventMessageListener,可以看到其继承了KeyspaceEventMessageListener,而KeyspaceEventMessageListener有一个需要重写的方法doHandleMessage(Message message),以及一个注册方法doRegister(RedisMessageListenerContainer container),在注册方法中向Reids消息监听器容器注册了当前的消息监听器。

public abstract class KeyspaceEventMessageListener implements MessageListener, InitializingBean, DisposableBean {
  
  // 订阅的主题,代表订阅所有的keyevent
  private static final Topic TOPIC_ALL_KEYEVENTS = new PatternTopic("__keyevent@*");
  
  /**
	 * Register instance within the container.
	 * 向容器注册当前实例
	 *
	 * @param container never {@literal null}.
	 */
	protected void doRegister(RedisMessageListenerContainer container) {
		listenerContainer.addMessageListener(this, TOPIC_ALL_KEYEVENTS);
	}
	
}

那我们就可以发散一下,根据Redis的官方文档,自定义一些其他的事件监听。

/**
 * Key删除事件
 */
@Component
public class RedisKeyDeleteEventMessageListener extends KeyspaceEventMessageListener {
  
  private static final Topic TOPIC = new PatternTopic("__keyevent@*__:del");
  
  public RedisKeyDeleteEventMessageListener(RedisMessageListenerContainer listenerContainer) {
    super(listenerContainer);
  }
  
  @Override
  protected void doRegister(RedisMessageListenerContainer listenerContainer) {
      listenerContainer.addMessageListener(this, TOPIC);
  }

  @Override
  protected void doHandleMessage(Message message) {
      System.out.println(message + "删除了");
  }
}
  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值