使用@EnableJpaRepositories时data.sql初始化脚本不执行如何解决?
问题描述
基于Spring Boot v2.3.4的应用依赖自定义核心库,库中包含实体类与业务逻辑。为了引入库中的实体和Repository,添加了带正确包路径的@EnableJpaRepositories和@EntityScan注解。
希望应用启动时通过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会调用org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer的initSchema()方法,执行data.sql初始化逻辑。
原本以为@EnableJpaRepositories会生成不支持该初始化逻辑的其他类型entityManagerFactory Bean,需要在保留@EnableJpaRepositories的前提下让data.sql正常执行,已知可以用Hibernate的import.sql实现,但需要明确底层原理和控制方法。
2021年9月28日更新1
进一步排查发现@EnableJpaRepositories并不会改变entityManagerFactory的实例类型,但会在创建org.springframework.scheduling.annotation.ProxyAsyncConfiguration Bean(即org.springframework.context.annotation.internalAsyncAnnotationProcessor Bean创建过程中)触发静默异常,问题实际和同时使用的@EnableAsync注解有关:移除该注解后,即便保留@EnableJpaRepositories,data.sql也能正常执行。
2021年9月28日更新2
问题根因
需同时满足4个条件才会复现该问题:
- 应用配置类上添加了
@EnableJpaRepositories注解 - 应用配置类上添加了
@EnableAsync注解 - 配置类实现了
AsyncConfigurer接口 - 配置类中通过@Autowired注入了
JpaRepository实例或依赖Repository的其他Bean
开启异步执行且实现AsyncConfigurer会让配置类早于普通Bean实例化,Spring为了注入Repository需要提前实例化entityManagerFactory Bean,此时会打印如下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)
其中漏加载的BeanPostProcessor就包含负责触发DataSourceSchemaCreatedEvent事件的DataSourceInitializedPublisher,缺少该事件会导致data-${platform}.sql脚本完全不会被处理。目前暂未确定@EnableJpaRepositories在其中的具体作用,但不添加该注解时问题不会出现。
复现代码示例
以下是最小复现代码(data.sql放在src/main/resources目录下):
@Entity public FileStore { ... } public interface FileStoreRepository extends JpaRepository<FileStore, Long> { } @Configuration @EnableAsync @EnableJpaRepositories public class Configuration implements AsyncConfigurer { @Autowired private FileStoreRepository fileStoreRepository; ... }
解决方案
目前已知有两种可行解决方案:
- 将
AsyncConfigurer、其重写方法以及@EnableAsync注解拆分到独立的配置类中 - 在注入的Repository上添加
@Lazy注解,示例如下:
@Lazy @Autowired private FileStoreRepository fileStoreRepository;
类似问题可参考Spring Boot官方Issue#15440。
内容的提问来源于stack exchange,提问作者Harry

