Redis发布/订阅(Pub/Sub)是一种通信机制,将数据推到某个消息管道中,其他客户端可以通过订阅这些管道来获取推送的信息,以此用于消息的传输。
Redis发布/订阅(Pub/Sub)主要由三部分组成:发布者(Publisher)、频道(Channel)、订阅者(Subscriber)。
Redis发布/订阅(Pub/Sub)的消息分到不同的频道,不需要知道什么样的订阅者订阅。订阅者对一个或多个频道感兴趣,只需要接收自身感兴趣的消息,不需要知道什么样的发布者发布。主要的目的就是解除消息的发布者与订阅者之间的耦合关系。
Redis发布订阅基于RedissonClient简单实现:
java
@Slf4j
@AllArgsConstructor
public class RedisCachePubSub {
private final RedissonClient redissonClient;
/**
* publish
* @param topic
* @param message
* @return
*/
public long publish(String topic, Object message) {
return redissonClient.getTopic(topic).publish(message);
}
/**
* publish
* @param topic
* @param codec
* @param message
* @return
*/
public long publish(String topic, Codec codec, Object message) {
return redissonClient.getTopic(topic, codec).publish(message);
}
/**
* publish async
* @param topic
* @param message
*/
public void publishAsync(String topic, Object message) {
redissonClient.getTopic(topic).publishAsync(message);
}
/**
* publish async
* @param topic
* @param codec
* @param message
*/
public void publishAsync(String topic, Codec codec, Object message) {
redissonClient.getTopic(topic, codec).publishAsync(message);
}
/**
* subscribe
* @param topic
* @param action
*/
public void subscribe(String topic, Action<Object> action) {
subscribe(topic, Object.class, (channel, message) -> action.invoke(message));
}
/**
* subscribe
* @param topic
* @param messageListener
*/
public void subscribe(String topic, MessageListener<Object> messageListener) {
subscribe(topic, Object.class, messageListener);
}
/**
* subscribe
* @param topic
* @param t
* @param messageListener
* @param <T>
*/
public <T> void subscribe(String topic, Class<T> t, MessageListener<T> messageListener) {
redissonClient.getTopic(topic).addListener(t, messageListener);
}
/**
* subscribe async
* @param topic
* @param action
*/
public void subscribeAsync(String topic, Action<Object> action) {
subscribeAsync(topic, Object.class, (channel, message) -> action.invoke(message));
}
/**
* subscribe async
* @param topic
* @param messageListener
*/
public void subscribeAsync(String topic, MessageListener<Object> messageListener) {
subscribeAsync(topic, Object.class, messageListener);
}
/**
* subscribe async
* @param topic
* @param t
* @param messageListener
* @param <T>
*/
public <T> void subscribeAsync(String topic, Class<T> t, MessageListener<T> messageListener) {
redissonClient.getTopic(topic).addListenerAsync(t, messageListener);
}
/**
* subscribe listener count
* @param topic
* @return
*/
public int subscribeListenerCount(String topic) {
return redissonClient.getTopic(topic).countListeners();
}
/**
* subscribe count
* @param topic
* @return
*/
public long subscribeCount(String topic) {
return redissonClient.getTopic(topic).countSubscribers();
}
/**
* subscribe remove all listener
* @param topic
*/
public void subscribeRemoveAllListeners(String topic) {
redissonClient.getTopic(topic).removeAllListeners();
}
/**
* pattern subscribe
* @param patternTopic
* @param action
*/
public void patternSubscribe(String patternTopic, Action<Object> action) {
patternSubscribe(patternTopic, Object.class, (pattern, channel, message) -> action.invoke(message));
}
/**
* pattern subscribe
* @param patternTopic
* @param patternMessageListener
*/
public void patternSubscribe(String patternTopic, PatternMessageListener<Object> patternMessageListener) {
patternSubscribe(patternTopic, Object.class, patternMessageListener);
}
/**
* pattern subscribe
* @param patternTopic
* @param t
* @param patternMessageListener
* @param <T>
*/
public <T> void patternSubscribe(String patternTopic, Class<T> t, PatternMessageListener<T> patternMessageListener) {
redissonClient.getPatternTopic(patternTopic).addListener(t, patternMessageListener);
}
/**
* pattern subscribe async
* @param patternTopic
* @param action
*/
public void patternSubscribeAsync(String patternTopic, Action<Object> action) {
patternSubscribeAsync(patternTopic, Object.class, (pattern, channel, message) -> action.invoke(message));
}
/**
* pattern subscribe async
* @param patternTopic
* @param patternMessageListener
*/
public void patternSubscribeAsync(String patternTopic, PatternMessageListener<Object> patternMessageListener) {
patternSubscribeAsync(patternTopic, Object.class, patternMessageListener);
}
/**
* pattern subscribe async
* @param patternTopic
* @param t
* @param patternMessageListener
* @param <T>
*/
public <T> void patternSubscribeAsync(String patternTopic, Class<T> t, PatternMessageListener<T> patternMessageListener) {
redissonClient.getPatternTopic(patternTopic).addListenerAsync(t, patternMessageListener);
}
/**
* pattern subscribe remove all listener
* @param patternTopic
*/
public void patternSubscribeRemoveAllListeners(String patternTopic) {
redissonClient.getPatternTopic(patternTopic).removeAllListeners();
}
}
自动配置:
java
@EnableCaching
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RedisCachePubSub redisCachePubSub(RedissonClient redissonClient) {
return new RedisCachePubSub(redissonClient);
}
@Bean
@ConditionalOnMissingBean
public RedissonClient redissonClient(RedisProperties redisProperties) {
Config config = new Config();
RedisProperties.Cluster cluster = redisProperties.getCluster();
if (null == cluster) {
String address = String.format("redis://%s:%d", redisProperties.getHost(), redisProperties.getPort());
SingleServerConfig serversConfig = config.useSingleServer().setAddress(address);
if (StrUtil.isNotBlank(redisProperties.getPassword())) {
serversConfig.setPassword(redisProperties.getPassword());
serversConfig.setDatabase(redisProperties.getDatabase());
}
} else {
List<String> nodeAddresses = cluster.getNodes().stream().map(node -> String.format("redis://%s", node))
.collect(Collectors.toList());
ClusterServersConfig clusterServersConfig = config.useClusterServers();
clusterServersConfig.setNodeAddresses(nodeAddresses);
if (StrUtil.isNotBlank(redisProperties.getPassword())) {
clusterServersConfig.setPassword(redisProperties.getPassword());
}
}
return Redisson.create(config);
}
}