springmvc订阅redis键过期消息通知

首先启用redis通知功能(ubuntu下操作):
编辑/etc/redis/redis.conf文件,添加或启用以下内容(过期通知):

notify-keyspace-events Ex

或者登陆redis-cli之后,输入以下命令:

config set notify-keyspace-events Ex

       因键空间通知功能需要耗费一定的CPU时间,因此默认情况下,该功能是关闭的。可以通过修改配置文件redis.conf,或者通过CONFIG SET命令,设置notify-keyspace-events选项,来启用或关闭该功能。

         该选项的值为空字符串时,该功能禁用,选项值为非空字符串时,启用该功能,非空字符串由特定的多个字符组成,每个字符表示不同的意义:

         K:keyspace事件,事件以__keyspace@<db>__为前缀进行发布;

         E:keyevent事件,事件以__keyevent@<db>__为前缀进行发布;

         g:一般性的,非特定类型的命令,比如del,expire,rename等;

         $:字符串特定命令;

         l:列表特定命令;

扫描二维码关注公众号,回复: 1086978 查看本文章

         s:集合特定命令;

         h:哈希特定命令;

         z:有序集合特定命令;

         x:过期事件,当某个键过期并删除时会产生该事件;

         e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件;

         A:g$lshzxe的别名,因此”AKE”意味着所有事件。

 

         注意,该选项的值中至少需要包含K或者E,否则不会发布任何事件。比如,如果需要开启针对列表的keyspace事件通知,则该选项需要配置为“Kl”;

 


expired事件通知的发送时间

         Redis 使用以下两种方式删除过期的键:

         a:当一个键被访问时,程序会对这个键进行检查,如果键已过期,则删除该键;

         b:系统会在后台定期扫描并删除那些过期的键;

 

         当过期键被以上两种方式中的任意一种发现并且删除时,才会产生expired事件通知。

         Redis不保证生存时间(TTL)变为 0 的键会立即被删除:如果没有命令访问这个键,或者设置生存时间的键非常多的话,那么在键的生存时间变为0,到该键真正被删除,这中间可能会有一段比较显著的时间间隔。

         因此,Redis产生expired事件通知的时间,是过期键被删除的时候,而不是键的生存时间变为 0 的时候。

=========================================================

不同命令产生的事件通知

         DEL 命令为每个被删除的键产生一个 del 事件;

         RENAME 产生两个事件:为源键产生一个 rename_from 事件,并为目标键产生一个 rename_to 事件;

         EXPIRE命令,在设置键的过期时间时产生一个 expire事件;当键因过期而被删除时,产生一个 expired事件;

         SORT命令,在带有 STORE 参数时产生一个 sortstore事件。如果 STORE 指示的用于保存排序结果的键已经存在,则原键会被删除,因此还会产生一个 del 事件;

         SET 以及它的所有变种(SETEX、SETNX和GETSET)都产生set事件。另外,SETEX命令还会产生expire 事件;

         MSET 命令,为每个键产生一个 set 事件;

         SETRANGE 产生一个 setrange 事件;

         INCR 、DECR、INCRBY和DECRBY都产生 incrby 事件;

         INCRBYFLOAT产生incrbyfloat事件;

         APPEND产生append事件;

         LPUSH和LPUSHX都产生单个 lpush 事件,即使有多个输入元素时,也是如此;

         RPUSH 和 RPUSHX 都产生单个rpush事件,即使有多个输入元素时,也是如此;

         RPOP 产生 rpop 事件,如果被弹出的元素是列表的最后一个元素,那么还会产生一个 del 事件;

         LPOP 产生 lpop 事件,如果被弹出的元素是列表的最后一个元素,那么还会产生一个 del 事件;

         LINSERT 产生一个 linsert 事件;

         LSET 产生一个 lset 事件;

         LREM产生一个lrem事件,如果该命令执行之后,列表键被清空,则还会产生一个 del 事件;

         LTRIM 产生一个ltrim事件,如果该命令执行之后,列表键被清空,则还会产生一个 del 事件;

         RPOPLPUSH 和 BRPOPLPUSH 产生一个 rpop 事件,以及一个 lpush 事件。两个命令都保证rpop事件在 lpush 事件之前发出。如果弹出元素之后,列表键被清空,则还会产生一个 del 事件;

         HSET 、 HSETNX 和 HMSET 都只产生一个 hset 事件;

         HINCRBY 产生一个 hincrby 事件;

         HINCRBYFLOAT 产生一个 hincrbyfloat 事件;

         HDEL 产生一个 hdel 通知。如果执行该命令之后,哈希键被清空,则还会产生一个del事件;

         SADD 产生一个 sadd 事件,即使有多个输入元素时,也是如此;

         SREM 产生一个 srem 事件,如果执行该命令之后,集合键被清空,则还会产生一个 del 事件;

         SMOVE 为源键产生一个 srem 事件,并为目标键产生一个sadd 事件;

         SPOP 产生一个 spop 事件。如果执行该命令之后,集合键被清空,则还会产生一个 del 事件;

         SINTERSTORE、SUNIONSTORE和SDIFFSTORE分别产生 sinterstore、sunionostore和sdiffstore 三种事件。如果用于保存结果的键已经存在,则还会产生一个 del 事件;

         ZINCR产生一个 zincr 事件;

         ZADD 产生一个 zadd事件,即使有多个输入元素时,也是如此;

         ZREM 产生一个 zrem 通知,即使有多个输入元素时,也是如此。如果执行 ZREM 之后,有序集合键被清空,则还会产生一个 del 事件;

         ZREMEBYSCORE 产生一个 zrembyscore事件,如果用于保存结果的键已经存在,则还会产生一个 del 事件。

         ZREMBYRANK 产生一个 zrembyrank事件,如果用于保存结果的键已经存在,则还会产生一个 del 事件。

         ZINTERSTORE 和 ZUNIONSTORE 分别产生 zinterstore 和 zunionstore 两种事件。如果用于保存结果的键已经存在,那么还会产生一个 del 事件。

         每当一个键因为过期而被删除时,产生一个 expired 事件。

         每当一个键因为 maxmemory策略而被删除并回收内存时,产生一个 evicted 事件。

 

         注意:所有命令都只在键真的被改动了之后,才会产生事件通知。比如,当srem命令试图删除不存在于集合的元素时,删除操作执行失败,因为没有真正的改动键,所以这一操作不会发送通知。



==========================================================

使用maven搭建好springmvc,和搭配好相应的redis的jar包,这个之前的博客中有,这里就不提了..

先写好相应的java处理该消息通知的类:

import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;

public class MyRedisKeyExpiredMessageDelegate    implements MessageListener {

	
	public void onMessage(Message message, byte[] pattern) {
		System.out.println("channel:" + new String(message.getChannel())
                + ",message:" + new String(message.getBody()));
    }
}


再在springmvc的xml配置里面搭配好相应的监听配置:
	<bean id="messageListener"
		class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
		<constructor-arg>
			<bean class="com.zww.common.redis.MyRedisKeyExpiredMessageDelegate" />
		</constructor-arg>
	</bean>
	<bean id="redisContainer"
		class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="messageListeners">
			<map>
				<entry key-ref="messageListener">
					<list>
						<!--  <bean class="org.springframework.data.redis.listener.ChannelTopic"> 
							<constructor-arg value="__keyevent@1__:expired" /> </bean>  -->
						<!-- <bean class="org.springframework.data.redis.listener.PatternTopic"> 
							<constructor-arg value="*" /> </bean> -->
						<bean class="org.springframework.data.redis.listener.PatternTopic">
							<constructor-arg value="__key*__:expired" />
						</bean>
					</list>
				</entry>
			</map>
		</property>
	</bean>

好了,这个时候可以启动服务器,随便插入一个键,设定好过期时间,就会看到打印的日志了


这里我在弄的时候有遇到这样一个坑,就是这个日志打印了两次,,仔细一看,是因为springmvc的配置加载了两次,主要原因还是因为web.xml里面的配置使springmvc加载两次,配置好相应的配置就好了....


不过因此也说明了,这个 

MyRedisKeyExpiredMessageDelegate     

 类最好是搞成单列,这样才能防止通知两次,使同样的代码执行两次,出现一些意外的情况,和耗费系统资源




此文参考 
http://blog.csdn.net/gqtcgq/article/details/50808729


http://www.bubuko.com/infodetail-1895361.html








猜你喜欢

转载自blog.csdn.net/u012930316/article/details/78587865