package com.example.demo;
public record Coffee(String id, String name) {
}
使用 Redis 进行响应式数据访问
本指南将引导您完成创建一个使用 Spring Data 与 Redis 交互的响应式功能应用程序的过程,并使用非阻塞 Lettuce 驱动程序。
您将构建什么
您将构建一个 Spring 应用程序,该应用程序使用 Spring Data Redis 和 Project Reactor 来响应式地与 Redis 数据存储进行交互,存储和检索 Coffee 对象而无需阻塞。该应用程序使用基于 Reactive Streams 规范的 Reactor Publisher 实现,即 Mono(用于返回 0 或 1 个值的 Publisher)和 Flux(用于返回 0 到 n 个值的 Publisher)。
你需要什么
-
大约 15 分钟
-
一个喜欢的文本编辑器或 IDE
-
Java 17 或更高版本
如何完成本指南
要在您的本地环境中查看最终结果,您可以执行以下操作之一
-
下载 并解压缩此指南的源代码仓库
-
使用 Git 克隆仓库:
git clone https://github.com/spring-guides/gs-spring-data-reactive-redis.git -
Fork 仓库,这样您就可以通过提交拉取请求来请求对本指南的更改
设置 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 开始
您可以使用此 预初始化项目 并单击 Generate 以下载 ZIP 文件。该项目已配置为适合本教程中的示例。
手动初始化项目
-
导航到 https://start.spring.io。此服务会为您拉取应用程序所需的所有依赖项,并为您完成大部分设置。
-
选择 Gradle 或 Maven 以及您想要使用的语言。本指南假设您选择了 Java。
-
单击 **Dependencies** 并选择 **Spring Reactive Web**、**Spring Data Reactive Redis** 和 **Docker Compose Support**。
-
单击生成。
-
下载生成的 ZIP 文件,这是一个已根据您的选择配置好的 Web 应用程序存档。
| 如果您的 IDE 集成了 Spring Initializr,您可以从 IDE 中完成此过程。 |
创建域类
创建一条记录,表示我们希望在我们咖啡目录中储备的咖啡类型
src/main/java/com/example/demo/Coffee.java
创建配置类
创建一个类,其中包含支持响应式 Redis 操作的 Spring Bean
src/main/java/com/example/demo/CoffeeConfiguration.java
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class CoffeeConfiguration {
@Bean
ReactiveRedisOperations<String, Coffee> redisOperations(ReactiveRedisConnectionFactory factory) {
Jackson2JsonRedisSerializer<Coffee> serializer = new Jackson2JsonRedisSerializer<>(Coffee.class);
RedisSerializationContext.RedisSerializationContextBuilder<String, Coffee> builder =
RedisSerializationContext.newSerializationContext(new StringRedisSerializer());
RedisSerializationContext<String, Coffee> context = builder.value(serializer).build();
return new ReactiveRedisTemplate<>(factory, context);
}
}
创建 Spring Bean 来加载数据
创建 Spring Bean 以在我们启动应用程序时加载示例数据
由于我们可能会(重新)启动应用程序多次,因此我们应该首先删除从先前执行中可能仍然存在的所有数据。我们通过 flushAll()(Redis)服务器命令来做到这一点。一旦我们刷新了任何现有数据,我们就创建一个小的 Flux,将每个咖啡名称映射到一个 Coffee 对象,并将其保存到响应式 Redis 存储库中。然后,我们查询存储库以获取所有值并显示它们。 |
src/main/java/com/example/demo/CoffeeLoader.java
package com.example.demo;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import jakarta.annotation.PostConstruct;
import java.util.UUID;
@Component
public class CoffeeLoader {
private final ReactiveRedisConnectionFactory factory;
private final ReactiveRedisOperations<String, Coffee> coffeeOps;
public CoffeeLoader(ReactiveRedisConnectionFactory factory, ReactiveRedisOperations<String, Coffee> coffeeOps) {
this.factory = factory;
this.coffeeOps = coffeeOps;
}
@PostConstruct
public void loadData() {
factory.getReactiveConnection().serverCommands().flushAll().thenMany(
Flux.just("Jet Black Redis", "Darth Redis", "Black Alert Redis")
.map(name -> new Coffee(UUID.randomUUID().toString(), name))
.flatMap(coffee -> coffeeOps.opsForValue().set(coffee.id(), coffee)))
.thenMany(coffeeOps.keys("*")
.flatMap(coffeeOps.opsForValue()::get))
.subscribe(System.out::println);
}
}
创建 RestController
创建一个 RestController 来为我们的应用程序提供外部接口
src/main/java/com/example/demo/CoffeeController.java
package com.example.demo;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
public class CoffeeController {
private final ReactiveRedisOperations<String, Coffee> coffeeOps;
CoffeeController(ReactiveRedisOperations<String, Coffee> coffeeOps) {
this.coffeeOps = coffeeOps;
}
@GetMapping("/coffees")
public Flux<Coffee> all() {
return coffeeOps.keys("*")
.flatMap(coffeeOps.opsForValue()::get);
}
}
运行应用程序
您可以通过 IDE 运行主方法。请注意,如果您从解决方案仓库克隆了项目,您的 IDE 可能会在错误的位置查找 compose.yaml 文件。您可以配置 IDE 以查找正确的位置,或者使用命令行运行应用程序。./gradlew bootRun 和 ./mvnw spring-boot:run 命令将启动应用程序并自动找到 compose.yaml 文件。
测试应用程序
在应用程序运行时,请从新的终端运行以下命令
curl https://:8080/coffees
您应该看到以下输出:
[
{
"id": "04ce0843-c9f8-40f6-942f-1ff643c1d426",
"name": "Jet Black Redis"
},
{
"id": "e2a0d798-5fa4-48a2-a45c-7770d8bb82bf",
"name": "Black Alert Redis"
},
{
"id": "13f13e3a-0798-44b7-8ae4-b319b227bb19",
"name": "Darth 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.host 和 spring.data.redis.port 分别默认为 localhost 和 6379。 |
构建应用程序
本节描述了运行本指南的不同方法
无论您选择如何运行应用程序,输出都应该相同。
要运行应用程序,您可以将应用程序打包为可执行 jar。./mvnw clean package 命令会将应用程序编译为可执行 jar。然后,您可以使用 java -jar target/demo-0.0.1-SNAPSHOT.jar 命令运行 jar。
或者,如果您有可用的 Docker 环境,您可以使用 Maven 或 Gradle 插件直接创建 Docker 镜像,使用 buildpacks。通过 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/demo:0.0.1-SNAPSHOT 命令运行应用程序。
--network 标志告诉 Docker 将我们的 guide 容器连接到我们的外部容器正在使用的现有网络。您可以在 Docker 文档中找到更多信息。 |
本地镜像支持
Spring Boot 还支持 编译为本地镜像,前提是您的机器上安装了 GraalVM 发行版。
然后,您可以运行 ./mvnw -Pnative native:compile 命令来生成本地镜像。构建完成后,您可以通过执行 target/demo 命令来以近乎即时的启动时间运行代码。
要使用 Maven 创建 本地镜像,您应该确保您的 pom.xml 文件使用了 spring-boot-starter-parent 和 org.graalvm.buildtools:native-maven-plugin。此插件应位于 <build> <plugins> 部分
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
您也可以使用 Buildpacks 创建 本地镜像。您可以运行 ./mvnw -Pnative spring-boot:build-image 命令来生成本地镜像。构建完成后,您可以使用 docker run --network container:guide-redis docker.io/library/demo:0.0.1-SNAPSHOT 命令启动应用程序。
在 Docker 中测试应用程序
如果您使用 Docker 指令(如前所示)运行应用程序,那么从终端或命令行运行简单的 curl 命令将不再有效。这是因为我们在一个从终端或命令行无法访问的 Docker 网络 中运行容器。要运行 curl 命令,我们可以启动第三个容器来运行我们的 curl 命令,并将其连接到同一个网络。
首先,获取一个与 Redis 容器和应用程序在同一网络上运行的新容器的交互式 shell
docker run --rm --network container:guide-redis -it alpine
接下来,在容器内的 shell 中,安装 curl
apk add curl
最后,您可以运行 curl 命令,如 测试应用程序 中所述。
总结
恭喜!您已开发了一个 Spring 应用程序,该应用程序使用 Spring Data 和 Redis 进行完全响应式、非阻塞的数据库访问!
想写新指南或为现有指南做贡献吗?请查看我们的贡献指南。
| 所有指南的代码均采用 ASLv2 许可,文字内容采用署名-禁止演绎知识共享许可。 |