Redis 不仅提供一个NoSQL数据库,同时还提供了一套消息系统。
下面我将Spring Boot使用Redis进行消息的发布与订阅具体的流程分享给大家
首先引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
1.发送消息
@Service
public class SendService {
private final static Logger logger = LoggerFactory.getLogger(SendService.class);
@Autowired
private StringRedisTemplate stringRedisTemplate;
public void sendMessage(String message,String message2) {
try {
logger.info("接收到消息:{},{}", message,message2);
stringRedisTemplate.convertAndSend("myChannel", message);
stringRedisTemplate.convertAndSend("myChannel2", message2);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
发送消息我们使用StringRedisTemplate来发送键和值均为字符串的消息。往myChannel和myChannel2两个主题发送消息
2.Redis 配置消息通道
创建一个Redis消息配置类
连接工程我们使用Spring Boot默认的RedisConnectionFactory
我们将在listenerAdapter方法中定义的Bean注册为一个消息监听者,它将监听myChannel和myChannel2两个主题的消息。
因为Receiver类是一个POJO,要将它包装在一个消息监听者适配器(实现了MessageListener接口),这样才能被监听者容器RedisMessageListenerContainer的addMessageListener方法添加到连接工厂中。有了这个适配器,当一个消息到达时,就会调用receiveMesage()方法进行响应。
@Configuration
public class RedisChannelConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter,
MessageListenerAdapter messageListenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
//订阅主题myChannel和myChannel2
container.addMessageListener(listenerAdapter, new PatternTopic("myChannel"));
container.addMessageListener(messageListenerAdapter, new PatternTopic("myChannel2"));
//这个container 可以添加多个 messageListener
return container;
}
@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
//这个地方 是给messageListenerAdapter 传入一个消息接受的处理器,利用反射的方法调用“receiveMessage”
//也有好几个重载方法,这边默认调用处理器的方法 叫handleMessage 可以自己到源码里面看
return new MessageListenerAdapter(receiver, "receiveMessage");
}
@Bean
MessageListenerAdapter messageListenerAdapter(Receiver receiver){
return new MessageListenerAdapter(receiver, "handleMessage");
}
}
注意:配置多通道 注入同类bean时 通过方法名来区别具体类
3.处理Receiver 消息接收类的receiveMessage()处理业务
@Service
public class Receiver {
public void receiveMessage(String message) {
//具体业务处理方法
}
public void handleMessage(String message) {
System.out.println("接收到消息信息"+message);
}
}
到这里一个完整的Spring Boot使用Redis进行消息的发布与订阅过程就打通了
*订阅发布对象
发布对象时 需要配置发布对象序列化 接收时也需要序列化操作
配置类
@Configuration
public class SubscriberConfig {
/**
* 注入消息监听适配器
*/
@Bean
public MessageListenerAdapter messageListenerAdapter(Receiver receiver){
return new MessageListenerAdapter(receiver, "receiveMessage");
}
/**
* 注入消息监听适配器
*/
@Bean
public MessageListenerAdapter messageListenerAdapter2(Receiver receiver){
return new MessageListenerAdapter(receiver, "handleMessage");
}
/**
* 注入消息监听容器
*/
@Bean
public RedisMessageListenerContainer getRedisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory, MessageListenerAdapter messageListenerAdapter, MessageListenerAdapter messageListenerAdapter2){
RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
redisMessageListenerContainer.addMessageListener(messageListenerAdapter, new PatternTopic("myChannel"));
redisMessageListenerContainer.addMessageListener(messageListenerAdapter2, new PatternTopic("myChannel2"));
//序列化对象(特别注意:发布的时候需要设置序列化;订阅方也需要设置序列化)
Jackson2JsonRedisSerializer seria = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
seria.setObjectMapper(objectMapper);
redisMessageListenerContainer.setTopicSerializer(seria);
return redisMessageListenerContainer;
}
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
//自定义序列化方式
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setKeySerializer(jackson2JsonRedisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
接收类
@Service
public class Receiver {
public void receiveMessage(String message) {
System.out.println("topic1接收到消息");
}
public void handleMessage(String message) {
//序列化对象(特别注意:发布的时候需要设置序列化;订阅方也需要设置序列化)
Jackson2JsonRedisSerializer seria = new Jackson2JsonRedisSerializer(User.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
seria.setObjectMapper(objectMapper);
User user = (User)seria.deserialize(message.getBytes());
System.out.println("接收到消息信息"+user.getUserName()+"信息"+user);
}
}
发布消息
@Autowired
private RedisTemplate<String,Object> redisTemplate;
User user = new User();
user.setRealName("六三");
user.setPassword("13434324234");
redisTemplate.convertAndSend("myChannel2", user);