本章带你使用Spring Data Redis实现发布和订阅Redis的消息。
本文目标
用Spring Boot构建一个应用,使用StringRedisTemplate发布一个字符串消息,使用MessageListenerAdapter订阅消息。
使用Spring Data Redis发布消息听起来有点奇怪,但是你会发现,Redis不仅提供了一个NoSQL数据存储,还有一个消息系统。
你需要
- 15分钟左右
- IntelliJ IDEA
- JDK 1.8+
- Maven 3.2+
- Redis服务器
启动一个Redis服务器
在创建一个消息应用之前,我们需要配置一个负责接收信息和发送信息的服务器。
Redis是一个开源,基于BSD协议,key-value存储系统,附带一个消息系统。
Windows版的安装方法可以参照这篇文章Redis下载及安装(windows版).
用Spring Initializr生成项目代码
对于所有的Spring应用,你都可以使用Spring Initializr生成基本的项目代码。Initializr提供了一个快速的方式去引入所有你需要的依赖,并且为你做了很多设置。当前例子需要 Spring Data Redis依赖。
具体设置如下图:
如上图所示,我们选择了Maven作为编译工具。你也可以选择Gradle来进行编译。然后我们分别把Group和Artifact设置为“com.hansy”和“messaging-redis”。
生成的pom.xml文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hansy</groupId>
<artifactId>messaging-redis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>messaging-redis</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
创建一个Redis消息接收器
在任何的基于消息的应用中,都有消息的发布者和消息的接受者。实现一个消息接收器,拥有一个可以响应消息的方法。代码如下:
package com.hansy.messagingredis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class Receiver {
private static final Logger logger = LoggerFactory.getLogger(Receiver.class);
private AtomicInteger counter = new AtomicInteger();
public void receiveMessage(String message) {
logger.info("Received <" + message + ">");
counter.incrementAndGet();
}
public int getCount() {
return counter.get();
}
}
Receiver是一个定义了接收接收消息的方法的POJO类。当你注册了一个Receiver作为消息监听器的话,消息处理方法的命名可以随意。
为了演示目的,这个Receiver只是对接收到的消息进行计数。
注册监听器和发送消息
Spring Data Redis提供了使用Redis来发送和接收消息的所有组件。
我们需要配置如下元素:
- 一个连接工厂
- 一个消息监听器的容器
- 一个Redis的Template
我们将会使用Redis的Template来发送消息,注册Receiver到消息监听器的容器来接收消息。连接工厂驱动Template和消息监听器的容器,让他们连接到Redis服务器。
本例使用了Spring Boot默认的RedisConnectionFactory,一个JedisConnectionFactory(基于jedis库)的实例。这个连接工厂注入了消息监听器的容器和Redis的Template,代码如下:
package com.hansy.messagingredis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
@SpringBootApplication
public class MessagingRedisApplication {
private static final Logger logger = LoggerFactory.getLogger(MessagingRedisApplication.class);
@Bean
Receiver receiver() {
return new Receiver();
}
@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
return new MessageListenerAdapter(receiver, "receiveMessage");
}
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, new PatternTopic("chat"));
return container;
}
@Bean
StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
public static void main(String[] args) throws InterruptedException {
ApplicationContext context = SpringApplication.run(MessagingRedisApplication.class, args);
StringRedisTemplate template = context.getBean(StringRedisTemplate.class);
Receiver receiver = context.getBean(Receiver.class);
while (receiver.getCount() == 0) {
logger.info("Sending message...");
template.convertAndSend("chat", "Hello from Redis!");
Thread.sleep(500L);
}
System.exit(0);
}
}
receiver()方法返回一个简单的Receiver对象,这个Receiver对象会被包装到listenerAdapter()方法返回的MessageListenerAdapter里面。再通过addMessageListener()方法添加到RedisMessageListenerContainer里面,对“chat”主题进行监听。当消息到达时,会调用Receiver对象的receiveMessage()方法。
监听消息需要连接工厂和消息监听容器等一些类。而发送消息,则需要RedisTemplate。我们使用了RedisTemplate的一个实现类StringRedisTemplate,使用Redis时,key和value都是String实例。
main()方法首先创建一个SpringApplication上下文。然后Application上下文启动一个消息监听容器,而消息监听容器开始监听消息。main()方法接着从上下文中取出一个StringRedisTemplate对象,然后用StringRedisTemplate在“chat”主题上发送一条文字消息“Hello from Redis!”。最后,关闭SpringApplication上下文,程序结束。
运行程序
运行程序,结果如下:
2020-07-30 16:45:15.548 INFO 24544 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2020-07-30 16:45:15.550 INFO 24544 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2020-07-30 16:45:15.576 INFO 24544 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 10ms. Found 0 Redis repository interfaces.
2020-07-30 16:45:18.077 INFO 24544 --- [ main] c.h.m.MessagingRedisApplication : Started MessagingRedisApplication in 3.157 seconds (JVM running for 6.317)
2020-07-30 16:45:18.079 INFO 24544 --- [ main] c.h.m.MessagingRedisApplication : Sending message...
2020-07-30 16:45:18.092 INFO 24544 --- [ container-2] com.hansy.messagingredis.Receiver : Received <Hello from Redis!>
小结
你已经用Spring Boot开发了一个使用Redis完成发布与订阅的程序。