Redis key過期監聽


通過開啟key過期的事件通知,當key過期時,會發布過期事件;我們定義key過期事件的監聽器,當key過期時,就能收到回調通知。

注意:

  1)由於redis key過期刪除是定時+惰性,當key過多時,刪除會有延遲,回調通知同樣會有延遲。

  2)且通知是一次性的,沒有ack機制,若收到通知后處理失敗,將不再收到通知。需自行保證收到通知后處理成功。

        3)通知只能拿到key,拿不到value

 

使用場景:

  1)實現延時隊列

    消息作為key,將需要延遲的時間設置為key的TTL,當key過期時,在監聽器收到通知,達到延遲的效果。

 

 

步驟:  

  1、修改 redis.conf / redis.window.conf 

  開啟 notify-keyspace-events Ex

 

  2、RedisConfig 中配置 Message Listener Containers (消息訂閱者容器)

   類似於Redis pub/sub 中 Message Listener Containers 的配置,區別少了監聽器的指定。

    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory) {
        // redis 消息訂閱(監聽)者容器
        RedisMessageListenerContainer messageListenerContainer = new RedisMessageListenerContainer();
        messageListenerContainer.setConnectionFactory(redisConnectionFactory);
        messageListenerContainer.addMessageListener(new ProductUpdateListener(), new PatternTopic("*.product.update"));
        return messageListenerContainer;
    }

 

  3、定義 key過期監聽器,繼承 KeyExpirationEventMessageListener

 

@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    /**
     * 創建RedisKeyExpirationListener bean時注入 redisMessageListenerContainer
     *
     * @param redisMessageListenerContainer RedisConfig中配置的消息監聽者容器bean
     */
    public RedisKeyExpirationListener(RedisMessageListenerContainer redisMessageListenerContainer) {
        super(redisMessageListenerContainer);
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String channel = new String(message.getChannel()); // __keyevent@*__:expired
        String pa = new String(pattern); // __keyevent@*__:expired
        String expiredKey = message.toString();
        System.out.println("監聽到過期key:" + expiredKey);
    }
}

 

 

  可以看到,其本質是Redis的發布訂閱,當key過期,發布過期消息(key)到Channel :__keyevent@*__:expired中,再看KeyExpirationEventMessageListener 源碼:

public class KeyExpirationEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware {

    // 發布key過期頻道的topic
    private static final Topic KEYEVENT_EXPIRED_TOPIC = new PatternTopic("__keyevent@*__:expired");

    private @Nullable
    ApplicationEventPublisher publisher;

    /**
     * 子類在由Spring容器創建bean的時候調用父類的此構造器,並傳入容器中的RedisMessageListenerContainer bean作為參數
     */
    public KeyExpirationEventMessageListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    /**
     * doRegister 在 KeyspaceEventMessageListener(實現了InitializingBean和 MessageListener) 中的init方中被調用
     * 將我們自定義的key過期監聽器添加到 消息監聽容器中
     */
    @Override
    protected void doRegister(RedisMessageListenerContainer listenerContainer) {
        listenerContainer.addMessageListener(this, KEYEVENT_EXPIRED_TOPIC);
    }

    /**
     * 發布key過期事件
     *
     * @param message 過期key
     */
    @Override
    protected void doHandleMessage(Message message) {
        publishEvent(new RedisKeyExpiredEvent(message.getBody()));
    }

    /**
     * 由Spring RedisKeyExpiredEvent事件監聽器執行實際上的redis key過期消息的發布
     */
    protected void publishEvent(RedisKeyExpiredEvent event) {

        if (publisher != null) {
            this.publisher.publishEvent(event);
        }
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }
}

 

  因此,我們定義的繼承了KeyExpirationEventMessageListener的redis key 過期監聽器本質上就是一個消息監聽器,監聽來自channel為__keyevent@*__:expired 上發布的消息

 

 

END.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM