Spring Boot 与 Docker
观察 GraphQL 的实际运行

本指南将引导您完成使用 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 开始

您可以使用这个预初始化项目,然后点击生成以下载一个 ZIP 文件。该项目已配置为适合本教程中的示例。

要手动初始化项目:

  1. 访问 https://start.spring.io。该服务会为您拉取应用程序所需的所有依赖项,并完成大部分设置工作。
  2. 选择 Gradle 或 Maven 以及您想要使用的语言。本指南假设您选择了 Java。
  3. 点击 Dependencies,然后选择 Spring Data RedisDocker Compose Support
  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()方法所要求的)。消息监听适配器还被配置为在消息到达时调用ReceiverreceiveMessage()方法。

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

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

运行应用程序

您可以通过您的 IDE 运行主方法。请注意,如果您从解决方案仓库克隆了项目,您的 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 文档

构建应用程序

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

  1. 构建并执行 JAR 文件

  2. 使用 Cloud Native Buildpacks 构建并执行 Docker 容器

无论您选择如何运行应用程序,输出结果应该是一致的。

要运行应用程序,您可以将应用程序打包为可执行的 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 将我们的指南容器附加到外部容器正在使用的现有网络上。您可以在 Docker 文档 中找到更多信息。

总结

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

另请参阅

以下指南可能也会有所帮助:

本页目录