使用 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 安装 - 手动运行 compose.yaml 文件,命令为 docker compose up

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

从 Spring Initializr 开始

您可以使用这个预初始化项目并单击“生成”以下载 ZIP 文件。此项目已配置为适合本教程中的示例。

手动初始化项目

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

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

  3. 单击“依赖项”并选择“Spring Data Redis”和“Docker Compose 支持”。

  4. 单击生成

  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,它是 LettuceConnectionFactory 的一个实例,基于 Lettuce Redis 库。连接工厂被注入到消息侦听器容器和 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 环境,您可以通过 Maven 或 Gradle 插件直接从 buildpacks 创建 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 将我们的 guide 容器连接到我们的外部容器正在使用的现有网络。您可以在 Docker 文档中找到更多信息。

总结

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

另请参阅

以下指南也可能有所帮助

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

所有指南的代码均采用 ASLv2 许可,文字内容采用署名-禁止演绎知识共享许可

获取代码