Basic knowledge of

Redis releases after 2.8.0 provide Keyspace Notifications functionality that allows customers to subscribe to Pub/Sub channels in order to receive events that affect redis datasets in some way

IO /topics/noti…

By default, redis notification events are turned off. Run the following command on the terminal to enable it: ‘

Where KEA means that all possible events are enabled

The code analysis

Springboot is integrated with Redis and directly priming packages

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
Copy the code

KeyspaceEventMessageListener to monitor all Key events private static final Topic TOPIC_ALL_KEYEVENTS = new PatternTopic(“__keyevent@*”); All keys under __keyevent@* db, __keyevent@db where db can be set

Enable redis notification events

private String keyspaceNotificationsConfigParameter = “EA”;

public void init() { Properties config = connection.getConfig(“notify-keyspace-events”); connection.setConfig(“notify-keyspace-events”, this.keyspaceNotificationsConfigParameter); this.doRegister(this.listenerContainer); }

DoRegister registers listening

public abstract class KeyspaceEventMessageListener implements MessageListener.InitializingBean.DisposableBean {
    private static final Topic TOPIC_ALL_KEYEVENTS = new PatternTopic("__keyevent@*");
    private final RedisMessageListenerContainer listenerContainer;
    private String keyspaceNotificationsConfigParameter = "EA";

    public KeyspaceEventMessageListener(RedisMessageListenerContainer listenerContainer) {
        Assert.notNull(listenerContainer, "RedisMessageListenerContainer to run in must not be null!");
        this.listenerContainer = listenerContainer;
    }

    public void onMessage(Message message, @Nullable byte[] pattern) {
        if(! ObjectUtils.isEmpty(message.getChannel()) && ! ObjectUtils.isEmpty(message.getBody())) {this.doHandleMessage(message); }}protected abstract void doHandleMessage(Message var1);

    public void init(a) {
        if (StringUtils.hasText(this.keyspaceNotificationsConfigParameter)) {
            RedisConnection connection = this.listenerContainer.getConnectionFactory().getConnection();

            try {
                Properties config = connection.getConfig("notify-keyspace-events");
                if(! StringUtils.hasText(config.getProperty("notify-keyspace-events"))) {
                    connection.setConfig("notify-keyspace-events".this.keyspaceNotificationsConfigParameter); }}finally{ connection.close(); }}this.doRegister(this.listenerContainer);
    }

    protected void doRegister(RedisMessageListenerContainer container) {
        this.listenerContainer.addMessageListener(this, TOPIC_ALL_KEYEVENTS);
    }

    public void destroy(a) throws Exception {
        this.listenerContainer.removeMessageListener(this);
    }

    public void setKeyspaceNotificationsConfigParameter(String keyspaceNotificationsConfigParameter) {
        this.keyspaceNotificationsConfigParameter = keyspaceNotificationsConfigParameter;
    }

    public void afterPropertiesSet(a) throws Exception {
        this.init(); }}Copy the code

KeyExpirationEventMessageListener to monitor Key failure event private static final Topic KEYEVENT_EXPIRED_TOPIC = new PatternTopic(“keyevent@*:expired”); Listen so the key under db is invalid


public class KeyExpirationEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware {
    private static final Topic KEYEVENT_EXPIRED_TOPIC = new PatternTopic("__keyevent@*__:expired");
    @Nullable
    private ApplicationEventPublisher publisher;

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

    protected void doRegister(RedisMessageListenerContainer listenerContainer) {
        listenerContainer.addMessageListener(this, KEYEVENT_EXPIRED_TOPIC);
    }

    protected void doHandleMessage(Message message) {
        this.publishEvent(new RedisKeyExpiredEvent(message.getBody()));
    }

    protected void publishEvent(RedisKeyExpiredEvent event) {
        if (this.publisher ! =null) {
            this.publisher.publishEvent(event); }}public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher; }}Copy the code

But it doesn’t implement listening for key insertion changes, so you’ll have to implement it yourself

Code implementation

KeySetEventMessageListener to monitor key set event private static final Topic KEYEVENT_SET_TOPIC = new PatternTopic(“keyevent@*:set”) Redis inserts and changes are set onMessage () and this is the code you want to implement. This is full library listening. You can also listen on a db keyevent@0:set separately

public class KeySetEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware {

    private static final Topic KEYEVENT_SET_TOPIC = new PatternTopic("__keyevent@*__:set");
    @Nullable
    private ApplicationEventPublisher publisher;

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


    @Override
    public void doRegister(RedisMessageListenerContainer listenerContainer) {
        listenerContainer.addMessageListener(this, KEYEVENT_SET_TOPIC);
    }


    @Override
    public void doHandleMessage(Message message) {
        this.publishEvent(new RedisKeyExpiredEvent(message.getBody()));

    }

    public void publishEvent(RedisKeyExpiredEvent event) {
        if (this.publisher ! =null) {
            this.publisher.publishEvent(event); }}@Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }
    
    @Override
    public void onMessage(Message message, byte[] pattern) {
// super.onMessage(message, pattern);
// TODO to implement the logic code
        System.out.println("Receive data :" + message.toString());
        System.out.println("Subscription channels :" + newString(message.getChannel())); }}Copy the code

If in order to maintain consistent style, also can write a subclass inherits the KeySetEventMessageListener doRegister () registered to monitor

@Component
public class MyEventMessageListener extends KeySetEventMessageListener {
    
// spring.redis.keyevent=__keyevent@13__:set
    
    @Value("${spring.redis.keyevent}")
    private String keyevent;

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

    @Override
    public void doRegister(RedisMessageListenerContainer listenerContainer) {
        listenerContainer.addMessageListener(this.new PatternTopic(keyevent));
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String redisKey = message.toString();
        // Regex is required to match the event to be processed
        if (StringUtils.isNotBlank(redisKey) && Pattern.matches("Regular matching", redisKey)) {
            System.out.println("Receive data :" + message.toString()+"--"+LocalDateTime.now());
// system.out.println (" Subscribe channel :" + new String(message.getChannel()));
            super.onMessage(message, pattern); }}}Copy the code