实现目标:
利用redis的pub/sub的消息机制,实现一级缓存的删除和清空的,
原因:
因为如果应用是分布式的系统,那么一级缓存的数据,是不能同步的,因此在清楚二级缓存的时候,
利用redis的消息机制来实现分布式系统数据的同步;
实现步骤:
1.定义消息对象的枚举类型
package org.github.roger.enumeration;
import lombok.Getter;
@Getter
public enum RedisPubSubMessageType {
/**
* 删除缓存
*/
EVICT("删除缓存"),
/**
* 清空缓存
*/
CLEAR("清空缓存");
private String label;
RedisPubSubMessageType(String label) {
this.label = label;
}
}
2. 定义消息对象
package org.github.roger.message;
import lombok.Data;
import org.github.roger.enumeration.RedisPubSubMessageType;
import java.io.Serializable;
@Data
public class RedisPubSubMessage implements Serializable {
/**
* 缓存名称
*/
private String cacheName;
/**
* 缓存key
*/
private Object key;
/**
* 消息类型
*/
private RedisPubSubMessageType messageType;
}
3.定义消息的发布者
package org.github.roger.listener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
@Slf4j
public class RedisPublisher {
private RedisPublisher() {
}
/**
* 发布消息到频道(Channel)
*
* @param redisTemplate redis客户端
* @param channelTopic 发布预订阅的频道
* @param message 消息内容
*/
public static void publisher(RedisTemplate<String, Object> redisTemplate, ChannelTopic channelTopic, Object message) {
redisTemplate.convertAndSend(channelTopic.toString(), message);
log.debug("redis消息发布者向频道【{}】发布了【{}】消息", channelTopic.toString(), message.toString());
}
}
4.定义消息的订阅者
package org.github.roger.listener;
import com.alibaba.fastjson.JSON;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.github.roger.MultiLayeringCache;
import org.github.roger.cache.ICache;
import org.github.roger.manager.AbstractCacheManager;
import org.github.roger.message.RedisPubSubMessage;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import java.util.Collection;
@Setter
@Slf4j
public class RedisMessageListener extends MessageListenerAdapter {
/**
* 缓存管理器
*/
private AbstractCacheManager cacheManager;
@Override
public void onMessage(Message message, byte[] pattern) {
super.onMessage(message, pattern);
// 解析订阅发布的信息,获取缓存的名称和缓存的key
RedisPubSubMessage redisPubSubMessage = (RedisPubSubMessage) cacheManager.getRedisTemplate()
.getValueSerializer().deserialize(message.getBody());
log.debug("redis消息订阅者接收到频道【{}】发布的消息。消息内容:{}", new String(message.getChannel()), JSON.toJSONString(redisPubSubMessage));
// 根据缓存名称获取多级缓存,可能有多个
Collection<ICache> caches = cacheManager.getCache(redisPubSubMessage.getCacheName());
for (ICache cache : caches) {
// 判断缓存是否是多级缓存
if (cache != null && cache instanceof MultiLayeringCache) {
switch (redisPubSubMessage.getMessageType()) {
case EVICT:
// 获取一级缓存,并删除一级缓存数据
((MultiLayeringCache) cache).getFirstCache().evict(redisPubSubMessage.getKey());
log.info("删除一级缓存{}数据,key={}", redisPubSubMessage.getCacheName(), redisPubSubMessage.getKey());
break;
case CLEAR:
// 获取一级缓存,并删除一级缓存数据
((MultiLayeringCache) cache).getFirstCache().clear();
log.info("清除一级缓存{}数据", redisPubSubMessage.getCacheName());
break;
default:
log.error("接收到没有定义的订阅消息频道数据");
break;
}
}
}
}
}