基于 Redis 的发布/订阅机制,我们可以很方便地实现一个"刷新本地缓存"的工具,适用于多个实例之间同步缓存刷新的场景。
以下是一个完整可落地的实现方案,基于 SpringBoot 和 RedisTemplate 实现:
✅ 第一步:配置 Redis 发布订阅
1. 配置 RedisMessageListenerContainer(订阅容器)
java
@Configuration
public class RedisPubSubConfig {
@Bean
public RedisMessageListenerContainer container(
RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, new ChannelTopic("cache:flush"));
return container;
}
@Bean
public MessageListenerAdapter listenerAdapter(CacheFlushSubscriber subscriber) {
return new MessageListenerAdapter(subscriber, "onMessage");
}
}
2. 订阅者:监听缓存刷新消息
java
@Component
public class CacheFlushSubscriber {
@Autowired
private LocalCacheManager localCacheManager;
public void onMessage(String message, String channel) {
if ("flush:all".equals(message)) {
localCacheManager.refreshAll();
} else if (message.startsWith("flush:")) {
String key = message.substring(6);
localCacheManager.refreshByKey(key);
}
}
}
3. 发布者:发送刷新指令
java
@Component
public class CacheFlushPublisher {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void publishFlushAll() {
redisTemplate.convertAndSend("cache:flush", "flush:all");
}
public void publishFlushByKey(String key) {
redisTemplate.convertAndSend("cache:flush", "flush:" + key);
}
}
✅ 第二步:本地缓存管理器(示例)
java
@Component
public class LocalCacheManager {
private final Map<String, Object> cache = new ConcurrentHashMap<>();
// 模拟从数据库加载
public void refreshAll() {
cache.clear();
cache.put("user:1", "Alice");
cache.put("user:2", "Bob");
System.out.println("本地缓存已刷新全部");
}
public void refreshByKey(String key) {
cache.remove(key);
cache.put(key, "refreshed-value-for-" + key);
System.out.println("本地缓存已刷新 key: " + key);
}
public Object get(String key) {
return cache.get(key);
}
}
✅ 第三步:测试接口(可选)
java
@RestController
@RequestMapping("/cache")
public class CacheController {
@Autowired
private CacheFlushPublisher publisher;
@GetMapping("/flush/all")
public String flushAll() {
publisher.publishFlushAll();
return "已发送刷新全部缓存指令";
}
@GetMapping("/flush/{key}")
public String flushByKey(@PathVariable String key) {
publisher.publishFlushByKey(key);
return "已发送刷新指定缓存指令:" + key;
}
@GetMapping("/get/{key}")
public Object get(@PathVariable String key) {
return localCacheManager.get(key);
}
}
✅ 使用方式
- 访问
/cache/flush/all
→ 所有实例本地缓存刷新 - 访问
/cache/flush/user:1
→ 仅刷新 key 为user:1
的缓存 - 访问
/cache/get/user:1
→ 获取本地缓存值
✅ 注意事项
- 发布/订阅消息不会持久化,如果实例未启动,将不会收到历史消息。
- 适用于轻量级广播,不适合高可靠性消息传递。
- 若需强一致性,建议使用消息队列(如 Kafka、RabbitMQ)。
如需扩展支持多个缓存区域、异步刷新、延迟刷新等功能,可在此基础上继续抽象封装。