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