此版本仍在开发中,尚未被视为稳定版。如需最新稳定版,请使用 Spring Data Commons 4.0.4spring-doc.cadn.net.cn

预先优化

本章介绍 Spring Data 的预编译(Ahead of Time,AOT)优化,这些优化基于Spring 的预编译优化spring-doc.cadn.net.cn

最佳实践

注解您的领域类型

在应用程序启动期间,Spring 会扫描类路径中的领域类,以对实体进行早期处理。 通过使用 Spring Data Store 特定的 @Table@Document@Entity 注解来标注您的领域类型,可以辅助初始的实体扫描,并确保这些类型被注册到 ManagedTypes 中以提供运行时提示(Runtime Hints)。 在原生镜像(native image)环境中无法进行类路径扫描,因此 Spring 必须使用 ManagedTypes 来确定初始的实体集合。spring-doc.cadn.net.cn

提前编译代码生成

提前编译(AOT)代码生成不仅限于与 GraalVM Native Image 配合使用,它在常规部署中也能带来优势,并有助于优化 JVM 上的启动性能。spring-doc.cadn.net.cn

通过AOT优化,某些决策(例如数据库方言)将在构建时被固化,并直接包含在应用程序的配置中。spring-doc.cadn.net.cn

如果启用了预先编译(Ahead of Time compilation),Spring Data 可以(取决于实际使用的模块)在构建的 AOT 阶段贡献多个组件。spring-doc.cadn.net.cn

上述每一项默认都是启用的。 然而,用户可以通过以下选项对配置进行微调。spring-doc.cadn.net.cn

spring.aot.data.accessors.enabledspring-doc.cadn.net.cn

用于控制是否为生成的类型/属性访问器贡献字节码的布尔标志spring-doc.cadn.net.cn

spring.aot.data.accessors.includespring-doc.cadn.net.cn

以逗号分隔的完全限定类名(FQCN)列表,用于为生成的类型/属性访问器提供字节码。 支持使用 Ant 风格的包含模式来匹配包名(例如 example.springdata.**)或类型名称进行包含。 如果某个类型同时被包含规则和排除规则匹配,则包含规则优先,该类型将被视为已包含。spring-doc.cadn.net.cn

spring.aot.data.accessors.excludespring-doc.cadn.net.cn

以逗号分隔的完全限定类名(FQCN)列表,用于跳过为生成的类型/属性访问器贡献字节码。 支持 Ant 风格的排除模式,可匹配包名(例如 example.springdata.**)或类型名称进行排除。 如果某个类型同时匹配包含规则和排除规则,则包含规则优先,该类型将被视为已包含。spring-doc.cadn.net.cn

spring.aot.repositories.enabledspring-doc.cadn.net.cn

用于控制是否为仓库接口生成源代码的布尔标志spring-doc.cadn.net.cn

spring.aot.[module-name].repositories.enabledspring-doc.cadn.net.cn

用于控制是否为特定模块(例如 cassandrajdbcjpamongodb)的 Repository 接口生成源代码的布尔标志spring-doc.cadn.net.cn

spring.aot.repositories.metadata.enabledspring-doc.cadn.net.cn

用于控制是否包含查询方法和实际查询字符串的 JSON 仓库元数据的布尔标志。 需要启用 spring.aot.repositories.enabledspring-doc.cadn.net.cn

提前编译存储库

提前编译(Ahead of Time)仓库仅适用于某些模块的命令式(非响应式)仓库接口。 符合资格的查询方法的判定标准因具体实现模块而异。spring-doc.cadn.net.cn

AOT 仓库是对 AOT 处理的一种扩展,通过预生成符合条件的查询方法实现。 对于开发者而言,查询方法在其调用时所执行的底层查询是不透明的。 AOT 仓库基于在构建时已知的派生查询、注解查询和命名查询,提供查询方法的实现。 此优化将查询方法的处理从运行时移至构建时,从而显著提升性能,因为应用程序每次启动时不再需要通过反射来分析查询方法。spring-doc.cadn.net.cn

生成的 AOT 仓库片段遵循命名规则 <Repository FQCN>Impl__AotRepository,并放置在与仓库接口相同的包中。spring-doc.cadn.net.cn

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

仓库元数据

AOT 处理会内省查询方法,并收集有关仓库查询的元数据。 Spring Data 将这些元数据存储在 JSON 文件中,文件名与源仓库相同,并位于同一包内。 仓库 JSON 元数据包含有关查询和片段的详细信息。 以下展示了针对下列仓库的一个示例:spring-doc.cadn.net.cn

{
  "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"
      }
    },
interface UserRepository extends CrudRepository<User, Integer> {

  List<User> findBy();

  Page<User> findByLastnameStartingWith(String lastname, Pageable page);

  @Query("select * from User where emailAddress = ?1")
  User findByEmailAddress(String username);
}

可以通过 spring.aot.repositories.metadata.enabled 标志来控制 JSON 元数据的生成。spring-doc.cadn.net.cn

原生镜像运行时提示

与常规的 JVM 运行时相比,以原生镜像(native image)方式运行应用程序需要额外的信息。 Spring Data 在 AOT(提前编译)处理过程中会为原生镜像的使用提供运行时提示(Runtime Hints)。 这些提示尤其包括:spring-doc.cadn.net.cn