跳到主要内容
版本:5.1.1

提前优化(AOT)

Doubao 中英对照 Ahead of Time Optimizations

本章介绍 Spring Data 的提前(AOT)优化,这些优化建立在 Spring 的提前优化 之上。

最佳实践​

为领域类型添加注解​

在应用启动期间,Spring 会扫描 classpath 中的领域类,以提前处理实体。通过使用 Spring Data 特定存储的 @Table、@Document 或 @Entity 注解为您的领域类型添加标注,您可以辅助初始实体扫描,并确保这些类型注册到 ManagedTypes 以用于运行时提示。在原生镜像环境中无法进行 classpath 扫描,因此 Spring 必须使用 ManagedTypes 来确定初始实体集。

提前代码生成​

提前代码生成并不局限于与 GraalVM 原生镜像配合使用,在常规部署场景中也能带来好处,并有助于优化 JVM 上的启动性能。

备注

通过 AOT 优化,某些决策(例如数据库方言)会在构建时固定,并按原样包含在应用配置中。

如果启用了提前编译,Spring Data 会在您构建的 AOT 阶段(取决于实际使用的模块)贡献若干组件。

  • 为生成的类型/属性访问器生成的字节码

  • 为已定义仓库接口生成的源代码

  • JSON 格式的仓库元数据

上述每一项默认均为启用。不过,您可以使用以下选项对配置进行微调。

spring.aot.data.accessors.enabled布尔标志,用于控制是否贡献为生成的类型/属性访问器生成的字节码
spring.aot.data.accessors.include以逗号分隔的 FQCN 列表,为其贡献为生成的类型/属性访问器生成的字节码。使用 Ant 风格的包含模式匹配包名(例如 example.springdata.**)或类型名以进行包含。如果某个类型同时被包含和排除匹配,则包含优先,该类型视为已包含。
spring.aot.data.accessors.exclude以逗号分隔的 FQCN 列表,跳过为其贡献为生成的类型/属性访问器生成的字节码。使用 Ant 风格的排除模式匹配包名(例如 example.springdata.**)或类型名以进行排除。如果某个类型同时被包含和排除匹配,则包含优先,该类型视为已包含。
spring.aot.repositories.enabled布尔标志,用于控制是否贡献仓库接口的源代码
spring.aot.[module-name].repositories.enabled布尔标志,用于控制是否为特定模块(例如 cassandra、jdbc、jpa、mongodb)贡献仓库接口的源代码
spring.aot.repositories.metadata.enabled布尔标志,用于控制是否贡献包含查询方法及实际查询字符串的 JSON 仓库元数据。需要启用 spring.aot.repositories.enabled。

提前仓库​

备注

提前仓库仅适用于某些模块的命令式(非响应式)仓库接口。识别符合条件查询方法的标准因实现模块而异。

AOT 仓库是 AOT 处理的一种扩展,它预先生成符合条件的查询方法实现。对于开发者而言,查询方法在调用时所执行的底层查询是不透明的。AOT 仓库基于构建时已知的派生查询、注解查询和命名查询来贡献查询方法实现。这种优化将查询方法处理从运行时移到构建时,从而带来显著的性能提升,因为查询方法无需在每次应用启动时通过反射进行分析。

生成的 AOT 仓库片段遵循 <Repository FQCN>Impl__AotRepository 的命名方案,并放置在与仓库接口相同的包中。

注意

请将 AOT 仓库类视为内部优化。不要在您的代码中直接使用它们,因为生成与实现细节在未来版本中可能会发生变化。

仓库元数据​

AOT 处理会内省查询方法,并收集有关仓库查询的元数据。Spring Data 将这些元数据存储在 JSON 文件中,这些文件以源仓库命名,并位于相同包中。仓库 JSON 元数据包含有关查询和片段的详细信息。以下面仓库为例:

{
"name": "example.springdata.UserRepository",
"module": "JDBC",
"type": "IMPERATIVE",
"methods": [
{
"name": "findBy",
"signature": "public abstract java.util.List<example.springdata.User> example.springdata.UserRepository.findBy()",
"query": {
"query": "SELECT * FROM User"
}
},
{
"name": "findByLastnameStartingWith",
"signature": "public abstract org.springframework.data.domain.Page<example.springdata.User> example.springdata.UserRepository.findByLastnameStartingWith(java.lang.String,org.springframework.data.domain.Pageable)",
"query": {
"query": "SELECT * FROM User u WHERE lastname LIKE :lastname",
"count-query": "SELECT COUNT(*) FROM User WHERE lastname LIKE :lastname"
}
},
{
"name": "findByEmailAddress",
"signature": "public abstract example.springdata.User example.springdata.UserRepository.findByEmailAddress(java.lang.String)",
"query": {
"query": "select * from User where emailAddress = ?1"
}
},
备注

可通过 spring.aot.repositories.metadata.enabled 标志控制是否创建 JSON 元数据。

原生镜像运行时提示​

与常规 JVM 运行时相比,将应用作为原生镜像运行需要额外的信息。Spring Data 会在 AOT 处理期间贡献运行时提示,供原生镜像使用。这些提示特别针对:

  • 审计

  • 用于捕获 classpath 扫描结果的 ManagedTypes

  • 仓库

    • 针对实体、返回类型和 Spring Data 注解的反射提示

    • 仓库片段

    • Querydsl Q 类

    • Kotlin 协程支持

  • Web 支持(针对 PagedModel 的 Jackson 提示)

MongoDB 专属提前优化特性​

MongoDB 提前仓库​

对于 Spring Data MongoDB,我们通常支持那些不由实现片段支撑、且无需实现片段的查询方法,但存在下文详述的若干限制。

备注

不支持使用 Project Reactor、Kotlin 协程等的响应式仓库接口。

支持的特性

  • 派生的 find、count、exists 和 delete 方法

  • 使用 @Query 注解的查询方法(不包含 SpEL 的方法)

  • 使用 @Aggregation、@Update 和 @VectorSearch 注解的方法

  • @Hint、@Meta 和 @ReadPreference 支持

  • Page、Slice 和 Optional 返回类型

  • DTO 与接口投影

限制

  • 不评估 @Meta.flags。

  • Collation 检测能力有限。

  • 不支持带模式匹配/大小写不敏感的 in 子句。

  • 自定义集合返回类型(例如 io.vavr.collection、org.eclipse.collections)尚不支持。

排除的方法

  • CrudRepository 及其他基础接口方法

  • Querydsl 和按示例查询方法

  • 从文件获取 MQL 的查询方法

提示

在使用 LIKE 关键字的派生查询中,建议使用 Pattern 而非 String 作为参数类型。

List<Person> findByLastnameLike(Pattern lastname);