编辑此页面

Infinispan 缓存

默认情况下,Quarkus Cache 使用 Caffeine 作为后端。也可以使用 Infinispan 代替。

此技术被认为是预览版。

预览版中,不保证向后兼容性和在生态系统中的存在。特定改进可能需要更改配置或 API,并且正在计划成为稳定版。欢迎在我们的邮件列表上提供反馈,或在我们的GitHub 问题跟踪器中提交问题。

有关可能的完整状态列表,请查看我们的常见问题解答条目

Infinispan 作为缓存后端

当使用 Infinispan 作为 Quarkus 缓存的后端时,每个缓存项都将存储在 Infinispan 中。

  • 后端使用<default> Infinispan 客户端(除非另有配置),因此请确保其配置已正确设置(或使用Infinispan 开发服务)。

  • 键和值都使用 Protobuf 和 Protostream 进行编组。

使用 Infinispan 后端

首先,将 quarkus-infinispan-cache 扩展添加到您的项目中

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-infinispan-cache</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-infinispan-cache")

然后,按照Quarkus 缓存指南中的详细说明,使用 @CacheResult 和其他缓存注解。

@GET
@Path("/{keyElement1}/{keyElement2}/{keyElement3}")
@CacheResult(cacheName = "expensiveResourceCache")
public ExpensiveResponse getExpensiveResponse(@PathParam("keyElement1") @CacheKey String keyElement1,
        @PathParam("keyElement2") @CacheKey String keyElement2, @PathParam("keyElement3") @CacheKey String keyElement3,
        @QueryParam("foo") String foo) {
    invocations.incrementAndGet();
    ExpensiveResponse response = new ExpensiveResponse();
    response.setResult(keyElement1 + " " + keyElement2 + " " + keyElement3 + " too!");
    return response;
}

@POST
@CacheInvalidateAll(cacheName = "expensiveResourceCache")
public void invalidateAll() {

}

配置 Infinispan 后端

Infinispan 后端使用 <default> Infinispan 客户端。有关访问 Infinispan 的配置,请参阅Infinispan 参考

在开发模式下,您可以使用Infinispan 开发服务

如果您想为缓存使用另一个 Infinispan,请按如下方式配置 client-name

quarkus.cache.infinispan.client-name=another

编组

在 Quarkus 中与 Infinispan 交互时,您可以轻松地在缓存中存储或检索数据时序列化和反序列化 Java 原始类型。Infinispan 不需要额外的编组配置。

@CacheResult(cacheName = "weather-cache") (1)
public String getDailyForecast(String dayOfWeek, int dayOfMonth, String city) { (2)
    return dayOfWeek + " will be " + getDailyResult(dayOfMonth % 4) + " in " + city;
}
1 请求将此方法执行缓存到 'weather-cache' 中
2 键结合了 String dayOfWeek、int dayOfMonth 和 String city。关联的值是 String 类型。

Quarkus 默认在 Infinispan 中使用 Protobuf 进行数据序列化。Infinispan 建议使用 Protobuf 作为组织数据的首选方式。因此,在使用普通 Java 对象 (POJO) 时,用户需要为 Infinispan 中的编组提供 schema。

编组 Java 类型

假设我们想使用 java.time.LocalDate 创建一个复合键。

@CacheResult(cacheName = "weather-cache") (1)
public String getDailyForecast(LocalDate date, String city) { (2)
    return date.getDayOfWeek() + " will be " + getDailyResult(date.getDayOfMonth() % 4) + " in " + city;
}
1 请求将此方法执行的响应缓存到 'weather-cache' 中
2 键结合了 java.util.LocalDate 日期和 String city。关联的值是 'String' 类型。

由于 Infinispan 在 Quarkus 中默认使用 Protobuf 对数据进行序列化,执行该代码将导致以下错误。

java.lang.IllegalArgumentException:
No marshaller registered for object of Java type java.time.LocalDate

Protobuf 本身不知道如何编组 java.time.LocalDate。幸运的是,Protostream 使用 @ProtoAdapter@ProtoSchema 为此问题提供了简单的解决方案。

@ProtoAdapter(LocalDate.class)
public class LocalDateAdapter {
    @ProtoFactory
    LocalDate create(String localDate) {
        return LocalDate.parse(localDate);
    }

    @ProtoField(1)
    String getLocalDate(LocalDate localDate) {
        return localDate.toString();
    }
}

@ProtoSchema(includeClasses = LocalDateAdapter.class, schemaPackageName = "quarkus")
public interface Schema extends GeneratedSchema {
}

编组您的 POJO

与 Java 类型一样,在使用 POJO 作为键或值时,您可以遵循此方法。

@CacheResult(cacheName = "my-cache") (1)
public ExpensiveResponse requestApi(String id) { (2)
    // very expensive call

    return new ExpensiveResponse(...);
}
1 请求将此方法执行的响应缓存到 'my-cache' 中
2 键是 String。关联的值是 org.acme.ExpensiveResponse 类型。

在这种情况下,您需要使用 @Proto@ProtoSchema 为您的 Java 类型定义 schema。此 schema 可以包含您在 Quarkus 应用程序中使用的所有类型和适配器。

@Proto
public record ExpensiveResponse(String result) {
}

@ProtoSchema(includeClasses = { ExpensiveResponse.class })
interface Schema extends GeneratedSchema {
}

Infinispan 参考的“基于注解的序列化”部分了解更多信息。

过期

您可以选择配置两个数据过期属性:寿命 (lifespan)最大空闲时间 (max-idle)

寿命

在 Infinispan 中,寿命 (lifespan) 是一个配置参数,它确定了一个条目(或对象)自创建或上次访问以来在缓存中可以存在的最长时间,之后它将被视为已过期并从缓存中移除。

当您为 Infinispan 缓存中的条目配置 寿命 (lifespan) 参数时,您指定了一个时间间隔。在条目添加到缓存或被访问(读取或写入)后,它的寿命倒计时就开始了。如果自条目创建或上次访问以来经过的时间超过了指定的“寿命”间隔,该条目将被视为已过期,并有资格被从缓存中驱逐。

quarkus.cache.infinispan.my-cache.lifespan=10s

最大空闲时间

当您为 Infinispan 缓存中的条目配置 最大空闲时间 (max-idle) 参数时,您指定了一个时间间隔。在缓存中的某个条目被访问(读取或写入)后,如果在指定的时间间隔内没有对该条目进行后续访问,则认为该条目处于空闲状态。一旦空闲时间超过 最大空闲时间 (max-idle) 间隔,该条目将被视为已过期,并可能被从缓存中驱逐。

quarkus.cache.infinispan.my-cache.max-idle=100s

构建时固定的配置属性 - 所有其他配置属性都可以在运行时覆盖

配置属性

类型

默认

用于与 Infinispan 通信的命名 Infinispan 客户端的名称。如果未设置,则使用默认的 Infinispan 客户端。

环境变量:QUARKUS_CACHE_INFINISPAN_CLIENT_NAME

显示更多

字符串

存储在缓存中的项目的默认寿命。

环境变量:QUARKUS_CACHE_INFINISPAN_LIFESPAN

显示更多

Duration 

存储在缓存中的项目的默认最大空闲时间。

环境变量:QUARKUS_CACHE_INFINISPAN_MAX_IDLE

显示更多

Duration 

应用于特定 Infinispan 缓存的其他配置(最高优先级)

类型

默认

存储在缓存中的项目的默认寿命。

环境变量:QUARKUS_CACHE_INFINISPAN__CACHE_NAME__LIFESPAN

显示更多

Duration 

存储在缓存中的项目的默认最大空闲时间。

环境变量:QUARKUS_CACHE_INFINISPAN__CACHE_NAME__MAX_IDLE

显示更多

Duration 

关于 Duration 格式

要编写持续时间值,请使用标准的 java.time.Duration 格式。有关更多信息,请参阅Duration#parse() Java API 文档

您还可以使用简化的格式,以数字开头

  • 如果该值仅为一个数字,则表示以秒为单位的时间。

  • 如果该值是一个数字后跟 ms,则表示以毫秒为单位的时间。

在其他情况下,简化格式将被转换为 java.time.Duration 格式以进行解析

  • 如果该值是一个数字后跟 hms,则在其前面加上 PT

  • 如果该值是一个数字后跟 d,则在其前面加上 P

相关内容