redis key expiration event to realize expiration reminder

Keywords: Redis Spring Java Apache

redis is turned off by default. It is not recommended to turn it on. This paper provides a reference. Key space notification is usually not enabled because of the additional cost of this process.

1. Enable redis configuration

#
#  notify-keyspace-events Ex
#
#  By default all notifications are disabled because most users don't need
#  this feature and the feature has some overhead. Note that if you don't
#  specify at least one of K or E, no events will be delivered.
notify-keyspace-events "Ex"
character Sending notice
K Key space notification. All notifications are prefixed with keyspace @ for key
E Key event notification. All notifications are prefixed with keyevent @ for event
g Notification of generic commands of unrelated types, such as DEL, express, RENAME, etc
$ Notification of string commands
l Notification of list commands
s Notification of collection commands
h Notification of hash command
z Notification of ordered collection commands
x Expiration event: sent every time an expiration key is deleted
e Evict event: sent whenever a key is deleted due to maxmemory policy
A Alias of parameter g$lshzxe, equivalent to All

There must be at least one K or E in the input parameters. Otherwise, no notice will be distributed no matter what the other parameters are. The italicized parts of the above table are general operations or events, while boldface represents operations of a specific data type. For example, "Kx" means that you want to monitor the failure event of a Key.

2. java implementation

2.1 pom configuration

Configuration of spring boot2

<dependencies>
	<!-- spring boot -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-redis</artifactId>
	</dependency>
	<!--spring2.0 Integrate redis what is needed common-pool2 -->
	<dependency>
		<groupId>org.apache.commons</groupId>
		<artifactId>commons-pool2</artifactId>
	</dependency>
</dependencies>

2.2 configuration

import java.lang.reflect.Method;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.spring.pro.constant.ChannelConstant;
import com.spring.pro.listener.KeyExpiredListener;
import com.spring.pro.listener.UserMsgListener;

/**
 * Cache management (for annotation)
 * @ClassName: CacheService
 * @Description:
 * @author ybw
 * @date 2017 5:44:52 p.m., April 20, 2010
 */
@Configuration
@EnableCaching // Boot cache
public class CacheConfig extends CachingConfigurerSupport {

	/**
	 * The strategy of generating key
	 * @return
	 */
	@Bean
	public KeyGenerator keyGenerator() {
		return new KeyGenerator() {
			@Override
			public Object generate(Object target, Method method, Object... params) {
				StringBuilder sb = new StringBuilder();
				sb.append(target.getClass().getName());
				sb.append(method.getName());
				for (Object obj : params) {
					sb.append(obj.toString());
				}
				return sb.toString();
			}
		};
	}

	/**
	 * Managed cache
	 * @param redisTemplate
	 * @return
	 */
	@Bean
	public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
		RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
				.fromConnectionFactory(redisConnectionFactory);
		return builder.build();
	}

	/**
	 * RedisTemplate To configure
	 * @param factory
	 * @return
	 */
	@Bean
	public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
		StringRedisTemplate template = new StringRedisTemplate(factory);
		// Using the Jackson library to serialize objects into JSON strings
		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
				Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);
		template.setValueSerializer(jackson2JsonRedisSerializer);
		template.afterPropertiesSet();
		return template;
	}

	// --------------------------pub/sub-----------------------------------------
	@Resource
	private KeyExpiredListener keyExpiredListener;

		
	@Bean
	public ChannelTopic expiredTopic() {
		return new ChannelTopic(ChannelConstant.expired);
	}

	@Bean
	public RedisMessageListenerContainer redisMessageListenerContainer(
			@Autowired RedisConnectionFactory redisConnectionFactory) {
		RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
		redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
		redisMessageListenerContainer.addMessageListener(keyExpiredListener, expiredTopic());
		return redisMessageListenerContainer;
	}
	// --------------------------pub/sub end------------------------------------------
}

3, monitor

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 * @Title: KeyExpiredListener.java
 * @Package com.spring.pro.listener
 * @Description:
 * @author ybwei
 * @date 2018 August 13, 2004 3:54:41 PM
 * @version V1.0
 */
@Component
public class KeyExpiredListener implements MessageListener {

	private final static Logger LOG = LoggerFactory.getLogger(UserMsgListener.class);
	@Autowired
	private RedisTemplate<?, ?> redisTemplate;

	@Override
	public void onMessage(Message message, byte[] pattern) {
		System.out.println("onPMessage pattern " + pattern + " " + " " + message);
		String channel = new String(message.getChannel());
		String str = (String) redisTemplate.getValueSerializer().deserialize(message.getBody());
		LOG.info("received message channel {}, body is {}.", channel, str);
	}

}

4, test

set aa bb
expire aa 2 #Set expiration time 2 seconds

A aa fter the failure, you will be notified.

Posted by ravi.kinjarapu on Sat, 04 Jan 2020 20:27:19 -0800