使用 Redis 进行消息传递

本指南将引导您了解如何使用 Spring Data Redis 发布和订阅通过 Redis 发送的消息。

您将构建什么

您将构建一个应用程序,该应用程序使用 StringRedisTemplate 发布字符串消息,并使用 MessageListenerAdapter 使 POJO 订阅该消息。

使用 Spring Data Redis 作为发布消息的手段听起来可能有些奇怪,但是,正如您将发现的,Redis 不仅提供 NoSQL 数据存储,还提供消息传递系统。

您需要什么

  • 大约 15 分钟

  • 首选的文本编辑器或 IDE

  • Java 17 或更高版本

如何完成本指南

像大多数 Spring 入门指南 一样,您可以从头开始完成每个步骤,也可以通过查看此仓库 中的代码直接跳到解决方案。

在本地环境中查看最终结果,您可以执行以下操作之一

设置 Redis 服务器

在构建消息传递应用程序之前,您需要设置处理接收和发送消息的服务器。本指南假设您使用 Spring Boot Docker Compose 支持。此方法的前提是您的开发机器上有一个可用的 Docker 环境,例如 Docker Desktop。添加一个依赖项 spring-boot-docker-compose,它会执行以下操作

  • 在您的工作目录中搜索 compose.yml 和其他常见的 compose 文件名

  • 使用发现的 compose.yml 调用 docker compose up

  • 为每个受支持的容器创建服务连接 Bean

  • 应用程序关闭时调用 docker compose stop

要使用 Docker Compose 支持,您只需按照本指南操作即可。根据您引入的依赖项,Spring Boot 会找到正确的 compose.yml 文件并在您运行应用程序时启动您的 Docker 容器。

如果您选择自己运行 Redis 服务器而不是使用 Spring Boot Docker Compose 支持,则有几种选择:- 下载服务器 并手动运行它 - 如果您使用 Mac,可以通过 Homebrew 安装 - 使用 docker compose up 手动运行 compose.yaml 文件

如果您选择这些替代方法中的任何一种,则应从 Maven 或 Gradle 构建文件中删除 spring-boot-docker-compose 依赖项。您还需要向 application.properties 文件添加配置,详情请参阅准备构建应用程序 部分。如前所述,本指南假定您使用 Spring Boot 中的 Docker Compose 支持,因此此时无需对 application.properties 进行额外更改。

从 Spring Initializr 开始

您可以使用此 预配置项目,然后点击 Generate 下载 ZIP 文件。此项目已配置好,适用于本教程中的示例。

手动初始化项目

  1. 导航到 https://start.spring.io。该服务会为您引入应用程序所需的所有依赖项并完成大部分设置。

  2. 选择 Gradle 或 Maven 以及您想使用的语言。本指南假设您选择了 Java。

  3. 点击 Dependencies(依赖项)并选择 Spring Data RedisDocker Compose Support(Docker Compose 支持)。

  4. 点击 Generate(生成)。

  5. 下载生成的 ZIP 文件,它是根据您的选择配置的应用程序归档文件。

如果您的 IDE 集成了 Spring Initializr,您可以直接在 IDE 中完成此过程。

创建 Redis 消息接收器

在任何基于消息的应用程序中,都有消息发布者和消息接收者。要创建消息接收者,请实现一个带有响应消息方法的接收者,如下例(来自 src/main/java/com/example/messagingredis/Receiver.java)所示

package com.example.messagingredis;

import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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 注册为消息监听器时,您可以随意命名处理消息的方法。

出于演示目的,接收者会计算收到的消息数量。这样,它就可以在收到消息时发出信号。

注册监听器并发送消息

Spring Data Redis 提供了使用 Redis 发送和接收消息所需的所有组件。具体来说,您需要配置

  • 连接工厂

  • 消息监听器容器

  • Redis 模板

您将使用 Redis 模板发送消息,并将 Receiver 注册到消息监听器容器中,以便它接收消息。连接工厂驱动模板和消息监听器容器,使它们能够连接到 Redis 服务器。

此示例使用 Spring Boot 的默认 RedisConnectionFactory,它是基于 Jedis Redis 库的 JedisConnectionFactory 实例。连接工厂被注入到消息监听器容器和 Redis 模板中,如下例(来自 src/main/java/com/example/messagingredis/MessagingRedisApplication.java)所示

package com.example.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
	RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
			MessageListenerAdapter listenerAdapter) {

		RedisMessageListenerContainer container = new RedisMessageListenerContainer();
		container.setConnectionFactory(connectionFactory);
		container.addMessageListener(listenerAdapter, new PatternTopic("chat"));

		return container;
	}

	@Bean
	MessageListenerAdapter listenerAdapter(Receiver receiver) {
		return new MessageListenerAdapter(receiver, "receiveMessage");
	}

	@Bean
	Receiver receiver() {
		return new Receiver();
	}

	@Bean
	StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
		return new StringRedisTemplate(connectionFactory);
	}

	public static void main(String[] args) throws InterruptedException {

		ApplicationContext ctx = SpringApplication.run(MessagingRedisApplication.class, args);

		StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
		Receiver receiver = ctx.getBean(Receiver.class);

		while (receiver.getCount() == 0) {

			LOGGER.info("Sending message...");
			template.convertAndSend("chat", "Hello from Redis!");
			Thread.sleep(500L);
		}

		System.exit(0);
	}
}

listenerAdapter 方法中定义的 Bean 会注册到 container 中定义的消息监听器容器中,并将监听 chat 主题上的消息。由于 Receiver 类是 POJO,因此需要将其包装在实现了 MessageListener 接口(addMessageListener() 需要)的消息监听器适配器中。消息监听器适配器也被配置为在消息到达时调用 Receiver 上的 receiveMessage() 方法。

连接工厂和消息监听器容器 Bean 是您监听消息所需的全部。要发送消息,您还需要一个 Redis 模板。这里,它被配置为一个 StringRedisTemplate Bean,它是 RedisTemplate 的一个实现,专注于 Redis 的常见用法,即键和值都是 String 实例。

main() 方法通过创建 Spring 应用程序上下文来启动所有内容。然后应用程序上下文启动消息监听器容器,消息监听器容器 Bean 开始监听消息。接着 main() 方法从应用程序上下文检索 StringRedisTemplate Bean,并使用它在 chat 主题上发送一条 Hello from Redis! 消息。最后,它关闭 Spring 应用程序上下文,应用程序结束。

运行应用程序

您可以通过 IDE 运行 main 方法。请注意,如果您从解决方案仓库克隆了项目,您的 IDE 可能会在错误的位置查找 compose.yaml 文件。您可以配置 IDE 在正确的位置查找,或者可以使用命令行运行应用程序。./gradlew bootRun./mvnw spring-boot:run 命令会启动应用程序并自动找到 compose.yaml 文件。

您应该会看到输出

yyyy-mm-ddT07:08:48.646-04:00  INFO 18338 --- [main] c.e.m.MessagingRedisApplication: Sending message...
yyyy-mm-ddT07:08:48.663-04:00  INFO 18338 --- [container-1] com.example.messagingredis.Receiver      : Received <Hello from Redis!>

准备构建应用程序

要在没有 Spring Boot Docker Compose 支持的情况下运行代码,您需要在本地运行 Redis。为此,您可以使用 Docker Compose,但必须首先对 compose.yaml 文件进行两项更改。首先,将 compose.yaml 中的 ports 条目修改为 '6379:6379'。其次,添加一个 container_name

compose.yaml 现在应该是

services:
  redis:
    container_name: 'guide-redis'
    image: 'redis:latest'
    ports:
      - '6379:6379'

现在您可以运行 docker compose up 来启动 Redis 服务器。现在您应该有一个外部 Redis 服务器,可以接受请求了。您可以使用您的外部 Redis 服务器重新运行应用程序,并看到相同的输出。

application.properties 文件中不需要配置,因为默认值与 compose.yaml 中的 Redis 服务器配置匹配。具体来说,spring.data.redis.hostspring.data.redis.port 属性默认分别为 localhost6379。有关连接到 Redis 的更多信息,请参阅 Spring Boot 文档

构建应用程序

本节介绍运行本指南的不同方法

无论您选择如何运行应用程序,输出都应该相同。

要运行应用程序,您可以将应用程序打包为可执行 JAR 文件。./mvnw clean package 命令将应用程序编译为可执行 JAR。然后您可以使用 java -jar target/messaging-redis-0.0.1-SNAPSHOT.jar 命令运行该 JAR 文件。

另外,如果您有可用的 Docker 环境,可以使用 buildpacks 直接从您的 Maven 或 Gradle 插件创建 Docker 镜像。使用 Cloud Native Buildpacks,您可以创建 Docker 兼容镜像,并在任何地方运行它们。Spring Boot 直接为 Maven 和 Gradle 提供了 buildpack 支持。这意味着您只需输入一个命令,就可以快速将合适的镜像导入本地运行的 Docker 守护进程。要使用 Cloud Native Buildpacks 创建 Docker 镜像,请运行 ./mvnw spring-boot:build-image 命令。启用 Docker 环境后,您可以使用 docker run --network container:guide-redis docker.io/library/messaging-redis:0.0.1-SNAPSHOT 命令运行应用程序。

--network 标志告诉 Docker 将我们的指南容器附加到外部容器正在使用的现有网络。您可以在 Docker 文档 中找到更多信息。

总结

恭喜!您刚刚使用 Spring 和 Redis 开发了一个发布-订阅应用程序。

另请参阅

以下指南也可能有所帮助

想撰写新指南或为现有指南做出贡献?请查看我们的 贡献指南

所有指南的代码均根据 ASLv2 许可发布,文字部分根据 署名-禁止演绎创作共用许可 发布。

获取代码