我的基于 Spring Boot (v2.3.4) 的应用程序使用包含核心实体和业务逻辑的自定义库。要使用这个库中的实体和存储库,我必须使用@EnableJpaRepositories
和@EntityScan
注释,并提供适当的包。
我还想在应用程序启动期间使用一些必需的数据(假设配置)初始化数据库。我发现 Spring Boot 允许使用data.sql
或data-${platform}.sql
文件来实现这一点。
长话短说,使用@EnableJpaRepositories
注释时,不会执行data.sql
脚本。
我在代码中做了一些挖掘,发现当不使用@EnableJpaRepositories
注释时entityManagerFactory
bean 是org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
类型。此 Bean 使用org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher
Bean 后处理器,该处理器触发org.springframework.boot.autoconfigure.jdbc.DataSourceSchemaCreatedEvent
事件,指示模式已创建。侦听此事件的类是org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker
。此侦听器从类调用initSchema()
org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer
方法。此方法负责使用脚本进行整个初始化data.sql
。
看起来设置@EnableJpaRepositories
注释会为entityManagerFactory
bean 创建不同类的实例,这不支持这种简单的初始化。
我的基本问题是如何使它都与@EnableJpaRepositories
注释一起工作。我总是可以使用Hibernate的import.sql
文件(工作正常),但我也试图了解引擎盖下到底发生了什么,我该如何控制它。
更新 128.09.2021
我做了进一步的调查,@EnableJpaRepositories
注释不会更改entityManagerFactory
的实例类型,但它在创建 Bean 时(在创建 Bean 期间)会导致静默异常 (?org.springframework.context.annotation.internalAsyncAnnotationProcessor
org.springframework.scheduling.annotation.ProxyAsyncConfiguration
)。看起来一切都与@EnableAsync
注释有关,我也在使用注释,但不知道它可能相关。但它是 - 删除它使初始化工作,即使使用@EnableJpaRepositories
.
更新 228.09.2021
我已经找到了我的问题的完整解释。必须满足 4 个条件才能重现问题:
- 应用程序配置中的
@EnableJpaRepositories
注释 - 应用程序配置中的
@EnableAsync
注释 - 配置实现
AsyncConfigurer
接口 - 自动连接任何
JpaRepository
存储库或任何其他注入存储库的 Bean
启用异步执行和实现AsyncConfigurer
使得整个配置在常规 bean 之前实例化。因为 Spring 必须注入存储库,所以它也需要实例化entityManagerFactory
bean。Spring 打印然后INFO
级别日志,如下所示:
Bean 'entityManagerFactoryBuilder' of type [org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
不符合资格BeanPostProcessors
之一DataSourceInitializedPublisher
负责触发DataSourceSchemaCreatedEvent
事件。如果没有该事件,data-${platform}.sql
脚本将根本不被处理。
我不确定@EnableJpaRepositories
在这个过程中的作用是什么,但没有它,问题就不会发生。
例
重现问题的最少代码(data.sql
位于src/main/resources
):
@Entity
public FileStore {
...
}
public interface FileStoreRepository extends extends JpaRepository<FileStore, Long> {
}
@Configuration
@EnableAsync
@EnableJpaRepositories
public class Configuration implements AsyncConfigurer {
@Autowired
private FileStoreRepository fileStoreRepository;
...
}
解决 方案
我知道有两种解决方案:
- 将
AsyncConfigurer
及其覆盖的方法和@EnableAsync
注释一起移动到单独的配置类 - 在自动连线的 bean 上使用
@Lazy
注释,如下所示:
@Lazy
@Autowired
private FileStoreRepository fileStoreRepository;
D. Ball@Allen也指出了类似的问题,可以在那里检查。
此行为已更改。
看看 操作指南。
加:
spring.jpa.defer-datasource-initialization: true