【Redis】基于redis实现订阅发布
背景
业务发展过程中,希望做到异步解耦,但是又不想引入MQ中间件,在中小型服务中,就可以考虑使用redis自带的订阅发布来解决这个问题。使用 Redis 实现消息的订阅和发布时,可以通过 Spring Boot 集成 Redis 来方便地实现。
引入redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置 Redis
在 application.properties
文件中,添加 Redis 配置:
spring.redis.host=localhost
spring.redis.port=6379
编写代码
-
Redis 配置
创建一个配置类来配置 Redis 的连接工厂和监听器:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; import org.springframework.data.redis.core.StringRedisTemplate; @Configuration public class RedisConfig { @Bean public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.addMessageListener(listenerAdapter, topic()); return container; } @Bean public MessageListenerAdapter listenerAdapter(RedisMessageSubscriber subscriber) { return new MessageListenerAdapter(subscriber, "onMessage"); } @Bean public ChannelTopic topic() { return new ChannelTopic("messageQueue"); } @Bean public StringRedisTemplate template(RedisConnectionFactory connectionFactory) { return new StringRedisTemplate(connectionFactory); } }
-
创建消息订阅者
编写一个类来处理收到的消息:
import org.springframework.stereotype.Service; @Service public class RedisMessageSubscriber { public void onMessage(String message, String channel) { System.out.println("Received message: " + message + " from channel: " + channel); } }
-
创建消息发布者
编写一个发布者通过 Redis 模板发送消息:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class MessagePublisher { @Autowired private StringRedisTemplate template; @Autowired private ChannelTopic topic; @GetMapping("/publish") public String publish(@RequestParam String message) { template.convertAndSend(topic.getTopic(), message); return "Message published: " + message; } }
如果需要监听多个channel,可以通过RedisConfig中添加新的消息适配器。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.core.StringRedisTemplate;
@Configuration
public class RedisConfig {
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter1,
MessageListenerAdapter listenerAdapter2) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter1, topic1());
container.addMessageListener(listenerAdapter2, topic2());
return container;
}
@Bean
public MessageListenerAdapter listenerAdapter1(RedisMessageSubscriber subscriber) {
return new MessageListenerAdapter(subscriber, "onMessage");
}
@Bean
public MessageListenerAdapter listenerAdapter2(RedisMessageSubscriber subscriber) {
return new MessageListenerAdapter(subscriber, "onMessage");
}
@Bean
public ChannelTopic topic1() {
return new ChannelTopic("channelOne");
}
@Bean
public ChannelTopic topic2() {
return new ChannelTopic("channelTwo");
}
@Bean
public StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
}
同时RedisMessageSubscriber 也可以书写多个来区分不同的业务场景下不同业务处理。