配置

本节描述如何通过以下任一方式配置 Spring Data JPA:

基于注解的配置

Spring Data JPA 仓库的支持可以通过 JavaConfig 和自定义 XML 命名空间来激活,如下例所示:

示例 1. 使用 JavaConfig 的 Spring Data JPA 仓库
@Configuration
@EnableJpaRepositories
@EnableTransactionManagement
class ApplicationConfig {

  @Bean
  public DataSource dataSource() {

    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
    return builder.setType(EmbeddedDatabaseType.HSQL).build();
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setGenerateDdl(true);

    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("com.acme.domain");
    factory.setDataSource(dataSource());
    return factory;
  }

  @Bean
  public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {

    JpaTransactionManager txManager = new JpaTransactionManager();
    txManager.setEntityManagerFactory(entityManagerFactory);
    return txManager;
  }
}
必须创建 `LocalContainerEntityManagerFactoryBean`,而不是直接创建 `EntityManagerFactory`,因为前者除了创建 `EntityManagerFactory` 之外,还参与异常转换机制。

前面的配置类使用 `spring-jdbc` 的 `EmbeddedDatabaseBuilder` API 设置嵌入式 HSQL 数据库。然后,Spring Data 设置 `EntityManagerFactory` 并使用 Hibernate 作为示例持久化提供程序。这里声明的最后一个基础架构组件是 `JpaTransactionManager`。最后,该示例使用 `@EnableJpaRepositories` 注解激活 Spring Data JPA 仓库,该注解本质上与 XML 命名空间具有相同的属性。如果未配置基本包,则使用配置类所在的包。

Spring 命名空间

Spring Data 的 JPA 模块包含一个自定义命名空间,允许定义仓库 bean。它还包含某些对 JPA 特殊的功能和元素属性。通常,JPA 仓库可以通过使用 `repositories` 元素来设置,如下例所示:

示例 2. 使用命名空间设置 JPA 仓库
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jpa="http://www.springframework.org/schema/data/jpa"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/jpa
    https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

  <jpa:repositories base-package="com.acme.repositories" />

</beans>
JavaConfig 和 XML,哪个更好?XML 是很久以前 Spring 的配置方式。在当今 Java、记录类型、注解等快速发展的时代,新项目通常尽可能多地使用纯 Java。虽然目前没有立即移除 XML 支持的计划,但某些最新功能可能无法通过 XML 使用。

使用 `repositories` 元素,它会为所有用 `@Repository` 注解的 bean 激活持久化异常转换,以便将 JPA 持久化提供程序抛出的异常转换为 Spring 的 `DataAccessException` 层次结构。

自定义命名空间属性

除了 `repositories` 元素的默认属性外,JPA 命名空间还提供其他属性,使您可以更详细地控制仓库的设置。

表 1. `repositories` 元素的自定义 JPA 特定属性

entity-manager-factory-ref

显式连接要与 `repositories` 元素检测到的仓库一起使用的 `EntityManagerFactory`。通常在应用程序中使用多个 `EntityManagerFactory` bean 时使用。如果未配置,Spring Data 会自动查找 `ApplicationContext` 中名为 `entityManagerFactory` 的 `EntityManagerFactory` bean。

transaction-manager-ref

显式连接要与 `repositories` 元素检测到的仓库一起使用的 `PlatformTransactionManager`。通常仅在配置了多个事务管理器或 `EntityManagerFactory` bean 时才需要。默认为当前 `ApplicationContext` 中定义的单个 `PlatformTransactionManager`。

如果未定义显式的 `transaction-manager-ref`,则 Spring Data JPA 需要一个名为 `transactionManager` 的 `PlatformTransactionManager` bean。

引导模式

默认情况下,Spring Data JPA 仓库是默认的 Spring bean。它们是单例作用域并被急切初始化。启动期间,它们会为了验证和元数据分析目的而与 JPA `EntityManager` 交互。Spring Framework 支持在后台线程中初始化 JPA `EntityManagerFactory`,因为此过程通常会在 Spring 应用程序中占用大量的启动时间。为了有效地利用后台初始化,我们需要确保 JPA 仓库尽可能晚地初始化。

从 Spring Data JPA 2.1 开始,您现在可以配置 `BootstrapMode`(通过 `@EnableJpaRepositories` 注解或 XML 命名空间),它采用以下值:

  • `DEFAULT`(默认)——除非显式用 `@Lazy` 注解,否则仓库会被急切实例化。只有在没有客户端 bean 需要仓库实例的情况下,延迟化才有效,因为这需要初始化仓库 bean。

  • `LAZY`——隐式声明所有仓库 bean 为延迟加载,并导致创建延迟初始化代理以注入到客户端 bean 中。这意味着,如果客户端 bean 只将实例存储在字段中并且在初始化期间不使用仓库,则不会实例化仓库。仓库实例将在第一次与仓库交互时初始化和验证。

  • `DEFERRED`——与 `LAZY` 的操作模式基本相同,但在响应 `ContextRefreshedEvent` 时触发仓库初始化,以便在应用程序完全启动之前验证仓库。

建议

如果您不使用异步 JPA 引导,请坚持使用默认引导模式。

如果您异步引导 JPA,`DEFERRED` 是一个合理的默认值,因为它将确保 Spring Data JPA 引导程序仅在 `EntityManagerFactory` 设置本身花费的时间长于初始化所有其他应用程序组件时才等待。尽管如此,它仍然确保在应用程序发出启动信号之前正确初始化和验证仓库。

LAZY 模式非常适合测试场景和本地开发。一旦您确信仓库能够正确引导,或者在测试应用程序其他部分的情况下,对所有仓库运行验证可能会不必要地增加启动时间。这同样适用于本地开发,您可能只需要访问需要初始化单个仓库的应用程序部分。