Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
我们需要Redis中的功能就是发布订阅的功能:
1、我们调用publish方法,进行广播,发送一条消息
2、当订阅者subscribe订阅这个广播的时候,就会收到这个message,然后去判断这个message告诉我了什么
注意:
1、当然订阅者和发布者都是可以是多个。
2、当长时间未发消息,订阅者会断开,所以我们需要定时发送心跳。
下边是上述的代码
订阅者
public class MySubscriber {
private static GedisCommands gedis = GedisUtils.getInstance();
public static void subscirbe() {
SubscribeCommands subscribe = gedis.getSubscribeCommands();
subscribe.getStatefulConnection().addListener(new SubscribeListener());
subscribe.subscribe("ChannelName");
}
private static class SubscribeListener implements RedisPubSubListener<String, String> {
@Override
public void message(String channel, String message) {
if ("heart".equals(message)) { // 心跳的消息
LocalLog.info("", "收到心跳,channel={},message={}", channel, message);
} else if ("change".equals(message)) { // mongo变更的消息
RedisCache.reload();
LocalLog.info("", "mongodb生变更,channel={},message={}", channel, message);
} else {
LocalLog.warn("", "频道={},收到异常message={}", channel, message);
}
}
@Override
public void message(String pattern, String channel, String message) {
message(channel, message);
}
@Override
public void subscribed(String channel, long count) {
LocalLog.info("", "subscribed 频道={},订阅频道数={}", channel, count);
}
@Override
public void psubscribed(String pattern, long count) {
LocalLog.info("", "psubscribed pattern={},订阅频道数={}", pattern, count);
}
@Override
public void unsubscribed(String channel, long count) {
LocalLog.info("", "unsubscribed 频道={},订阅频道数={}", channel, count);
}
@Override
public void punsubscribed(String pattern, long count) {
LocalLog.info("", "punsubscribed pattern={},订阅频道数={}", pattern, count);
}
}
}
发布者
public class MyPublisher {
private static GedisCommands gedis = GedisUtils.getInstance();
private static PublishCommands publish = gedis.getPublishCommands();
/**
* 信息变更通知发布
* @param channel 频道
* @param message 发生变动的事件流定义信息JSON串
*/
public static void publish(String channel, String message) {
try {
// 发布事件配置信息更新通知
publish.publish(channel, message);
} catch (Exception e) {
LocalLog.error("", "发布订阅=>出错", e);
}
}
}
mongo的增删改查的dao中一个方法
@Override
public void updateUser(User user) {
try {
User oldUser = findUserById(user.getId());
if (oldUser != null) {
mongoDBDao.save(user);
}
// 变更通知,通知订阅者
String jsonStr = JSON.toJSONString(user);
MyPublisher.publish("ChannelName", "change");
LocalLog.info("事件定义=>更改事件定义成功,message =" + jsonStr);
} catch (Exception e) {
LocalLog.error("事件定义=>更新事件定义出错,cause=" + ThrowableUtils.cause(e));
}
}
维持心跳的定时器
**
* redis发布订阅维持心跳。一分钟发送一条消息
*/
public class HeartBeatTask {
private static GedisCommands gedis = GedisUtils.getInstance();
private static ScheduledExecutorService service = new ScheduledThreadPoolExecutor(1);
public static void startup() {
try {
// 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间
service.scheduleAtFixedRate(() -> {
boolean lock = new ZKLock("heartbeat" + EventBaseConstants.SEPARATOR + "redis").getLock();
if (lock) {
try {
LocalLog.info("", "redis发布订阅=>发布心跳信息");
MyPublisher.publish("MyChannel",
"heart");
} catch (Exception e) {
LocalLog.error("redis发布订阅维持心跳任务执行异常", e);
}
}
}, 0, 1, TimeUnit.MINUTES);
} catch (Exception e) {
LocalLog.error("redis发布订阅维持心跳任务执行异常", e);
}
}
public static void shutdown() {
service.shutdownNow();
}
}