使用 Redis 客户端
本指南演示了 Quarkus 应用程序如何使用 Redis Client 扩展连接到 Redis 服务器。
此技术被认为是稳定的。 由于是稳定的,因此非常重视向后兼容性和在生态系统中的存在性。 有关可能的完整状态列表,请查看我们的常见问题解答条目。 |
先决条件
要完成本指南,您需要
-
大约 15 分钟
-
一个 IDE
-
已安装 JDK 17+ 并正确配置了
JAVA_HOME
-
Apache Maven 3.9.9
-
如果您想使用它,可以选择 Quarkus CLI
-
如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置
-
一个有效的 Docker 环境
架构
在本指南中,我们将公开一个简单的 Rest API,使用 INCRBY
命令来增加数字。在此过程中,我们将了解如何使用其他 Redis 命令,例如 GET
、SET
(来自字符串组)、DEL
和 KEYS
(来自键组)。
我们将使用 Quarkus Redis 扩展来连接和与 Redis 交互。
解决方案
我们建议您按照以下章节中的说明,逐步创建应用程序。但是,您可以直接转到完整的示例。
克隆 Git 存储库:git clone https://github.com/quarkusio/quarkus-quickstarts.git
,或下载一个存档。
解决方案位于 redis-quickstart
目录中。
创建 Maven 项目
首先,我们需要一个新项目。使用以下命令创建一个新项目
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用 Powershell,请将
-D
参数括在双引号中,例如"-DprojectArtifactId=redis-quickstart"
此命令会生成一个新项目,导入 Redis 扩展。
如果您已经配置了 Quarkus 项目,可以通过在项目根目录中运行以下命令将 redis-client
扩展添加到您的项目中
quarkus extension add redis-client
./mvnw quarkus:add-extension -Dextensions='redis-client'
./gradlew addExtension --extensions='redis-client'
这会将以下内容添加到您的构建文件中
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-redis-client</artifactId>
</dependency>
implementation("io.quarkus:quarkus-redis-client")
创建 Increment POJO
我们将使用 Increment
POJO 来模拟我们的增量。创建 src/main/java/org/acme/redis/Increment.java
文件,内容如下
package org.acme.redis;
public class Increment {
public String key; (1)
public long value; (2)
public Increment(String key, long value) {
this.key = key;
this.value = value;
}
public Increment() {
}
}
1 | 将用作 Redis 键的键 |
2 | Redis 键持有的值 |
创建 Increment Service
我们将创建一个 IncrementService
类,它将扮演 Redis 客户端的角色。通过此类,我们将能够执行 SET
、GET
、DEL
、KEYS
和 INCRBY
Redis 命令。
创建 src/main/java/org/acme/redis/IncrementService.java
文件,内容如下
package org.acme.redis;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import io.quarkus.redis.datasource.ReactiveRedisDataSource;
import io.quarkus.redis.datasource.RedisDataSource;
import io.quarkus.redis.datasource.keys.KeyCommands;
import io.quarkus.redis.datasource.keys.ReactiveKeyCommands;
import io.quarkus.redis.datasource.string.StringCommands;
import io.smallrye.mutiny.Uni;
@ApplicationScoped
public class IncrementService {
// This quickstart demonstrates both the imperative
// and reactive Redis data sources
// Regular applications will pick one of them.
private ReactiveKeyCommands<String> keyCommands; (1)
private ValueCommands<String, Long> countCommands; (2)
public IncrementService(RedisDataSource ds, ReactiveRedisDataSource reactive) { (3)
countCommands = ds.value(Long.class); (4)
keyCommands = reactive.key(); (5)
}
long get(String key) {
Long value = countCommands.get(key); (6)
if (value == null) {
return 0L;
}
return value;
}
void set(String key, Long value) {
countCommands.set(key, value); (7)
}
void increment(String key, Long incrementBy) {
countCommands.incrby(key, incrementBy); (8)
}
Uni<Void> del(String key) {
return keyCommands.del(key) (9)
.replaceWithVoid();
}
Uni<List<String>> keys() {
return keyCommands.keys("*"); (10)
}
}
1 | 用于操作键的字段 |
2 | 用于操作计数器的字段 |
3 | 注入命令式和响应式数据源 |
4 | 检索用于操作计数器的命令 |
5 | 检索用于操作键的命令 |
6 | 检索与给定键关联的值。如果为 null ,则返回 0。 |
7 | 设置与给定键关联的值 |
8 | 递增与给定键关联的值 |
9 | 删除一个键(及其关联的值) |
10 | 列出所有键 |
创建 Increment Resource
创建 src/main/java/org/acme/redis/IncrementResource.java
文件,内容如下
package org.acme.redis;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.DELETE;
import java.util.List;
import io.smallrye.mutiny.Uni;
@Path("/increments")
public class IncrementResource {
@Inject
IncrementService service;
@GET
public Uni<List<String>> keys() {
return service.keys();
}
@POST
public Increment create(Increment increment) {
service.set(increment.key, increment.value);
return increment;
}
@GET
@Path("/{key}")
public Increment get(String key) {
return new Increment(key, service.get(key));
}
@PUT
@Path("/{key}")
public void increment(String key, long value) {
service.increment(key, value);
}
@DELETE
@Path("/{key}")
public Uni<Void> delete(String key) {
return service.del(key);
}
}
创建测试类
编辑 pom.xml
文件以添加以下依赖项
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
创建 src/test/java/org/acme/redis/IncrementResourceTest.java
文件,内容如下
package org.acme.redis;
import static org.hamcrest.Matchers.is;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
import static io.restassured.RestAssured.given;
import io.restassured.http.ContentType;
@QuarkusTest
public class IncrementResourceTest {
@Test
public void testRedisOperations() {
// verify that we have nothing
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(0));
// create a first increment key with an initial value of 0
given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.body("{\"key\":\"first-key\",\"value\":0}")
.when()
.post("/increments")
.then()
.statusCode(200)
.body("key", is("first-key"))
.body("value", is(0));
// create a second increment key with an initial value of 10
given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.body("{\"key\":\"second-key\",\"value\":10}")
.when()
.post("/increments")
.then()
.statusCode(200)
.body("key", is("second-key"))
.body("value", is(10));
// increment first key by 1
given()
.contentType(ContentType.JSON)
.body("1")
.when()
.put("/increments/first-key")
.then()
.statusCode(204);
// verify that key has been incremented
given()
.accept(ContentType.JSON)
.when()
.get("/increments/first-key")
.then()
.statusCode(200)
.body("key", is("first-key"))
.body("value", is(1));
// increment second key by 1000
given()
.contentType(ContentType.JSON)
.body("1000")
.when()
.put("/increments/second-key")
.then()
.statusCode(204);
// verify that key has been incremented
given()
.accept(ContentType.JSON)
.when()
.get("/increments/second-key")
.then()
.statusCode(200)
.body("key", is("second-key"))
.body("value", is(1010));
// verify that we have two keys in registered
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(2));
// delete first key
given()
.accept(ContentType.JSON)
.when()
.delete("/increments/first-key")
.then()
.statusCode(204);
// verify that we have one key left after deletion
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(1));
// delete second key
given()
.accept(ContentType.JSON)
.when()
.delete("/increments/second-key")
.then()
.statusCode(204);
// verify that there is no key left
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(0));
}
}
开始运行
如果您按照说明操作,应该已经运行了 Redis 服务器。然后,只需使用以下命令运行应用程序
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
打开另一个终端并运行 curl https://:8080/increments
命令。
与应用程序交互
正如我们上面所见,API 公开了五个 Rest 端点。在本节中,我们将看到如何初始化一个增量、查看当前增量的列表、根据键增量一个值、检索增量的当前值,以及最后删除一个键。
创建一个新的增量
curl -X POST -H "Content-Type: application/json" -d '{"key":"first","value":10}' https://:8080/increments (1)
1 | 我们创建第一个增量,键为 first ,初始值为 10 。 |
运行上述命令应返回以下结果
{
"key": "first",
"value": 10
}
检索新的增量
要使用键检索增量,我们需要运行以下命令
curl https://:8080/increments/first (1)
1 | 运行此命令应返回以下结果 |
{
"key": "first",
"value": 10
}
根据键递增值
要递增值,请运行以下命令
curl -X PUT -H "Content-Type: application/json" -d '27' https://:8080/increments/first (1)
1 | 将 first 的值增加 27。 |
现在,运行命令 curl https://:8080/increments/first
应返回以下结果
{
"key": "first",
"value": 37 (1)
}
1 | 我们看到 first 键的值现在是 37 ,这正好是 10 + 27 的结果,快速计算。 |
删除键
使用以下命令,根据键删除增量。
curl -X DELETE https://:8080/increments/first (1)
1 | 删除 first 增量。 |
现在,运行命令 curl https://:8080/increments
应返回一个空列表 []
为生产配置
此时,Quarkus 使用 Redis Dev Service 来运行 Redis 服务器并配置应用程序。但是,在生产环境中,您将运行自己的 Redis(或使用云服务)。
让我们使用以下命令在端口 6379 上启动一个 Redis 服务器
docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 --name redis_quarkus_test -p 6379:6379 redis:5.0.6
然后,打开 src/main/resources/application.properties
文件并添加
%prod.quarkus.redis.hosts=redis://:6379
打包并在 JVM 模式下运行
您可以将应用程序作为常规 jar 文件运行。
首先,我们需要打包它
quarkus build
./mvnw install
./gradlew build
此命令将启动一个 Redis 实例以执行测试。 |
然后运行它
java -jar target/quarkus-app/quarkus-run.jar
原生运行
您也可以从此应用程序创建本地可执行文件,而无需进行任何源代码更改。本地可执行文件消除了对 JVM 的依赖:运行应用程序所需的一切都包含在可执行文件中,从而使应用程序以最少的资源开销运行。
编译本地可执行文件需要更长的时间,因为 GraalVM 执行了额外的步骤来删除不必要的代码路径。使用 native
配置文件来编译本地可执行文件
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
构建完成后,您可以使用以下命令运行可执行文件
./target/redis-quickstart-1.0.0-SNAPSHOT-runner
更进一步
要了解有关 Quarkus Redis 扩展的更多信息,请参阅Redis 扩展参考指南。