SpringBoot从2.7.2升级到3.1.5后循环依赖问题求助
问题核心
升级后出现循环依赖链:webSecurityConfig→securityService→userRepository→jpaSharedEM_entityManagerFactory→liquibase,虽已改为Setter注入并开启spring.main.allow-circular-references=true,但仍报错创建userRepository时无法解析jpaSharedEM_entityManagerFactory的引用,本质是Liquibase与JPA EntityManagerFactory的初始化顺序冲突,且Security相关Bean过早触发了Repository的初始化。
排查与解决步骤
1. 修正Liquibase初始化的注解逻辑
Spring Boot 3.x中@DependsOnDatabaseInitialization的语义是标记Bean需等待数据库初始化完成后创建,但你的自定义Liquibase本身就是数据库初始化组件,加这个注解会导致Liquibase的初始化被后置,反而让依赖它的EntityManagerFactory无法正常创建。
修改LiquibaseConfig,移除@DependsOnDatabaseInitialization注解:
@Configuration @EnableConfigurationProperties(LiquibaseProperties.class) public class LiquibaseConfig { @Value("${db.schema:}") private String dbSchema; // 移除@DependsOnDatabaseInitialization @Bean public CustomSpringLiquibase liquibase(DataSource dataSource, LiquibaseProperties properties) { SpringLiquibase liquibase = new SpringLiquibase(); liquibase.setChangeLog(properties.getChangeLog()); liquibase.setContexts(properties.getContexts()); liquibase.setDataSource(dataSource); if (StringUtils.isNoneBlank(dbSchema)) { liquibase.setDefaultSchema(dbSchema); } else { liquibase.setDefaultSchema(properties.getDefaultSchema()); } liquibase.setDropFirst(properties.isDropFirst()); liquibase.setShouldRun(properties.isEnabled()); liquibase.setLabels(properties.getLabels()); liquibase.setChangeLogParameters(properties.getParameters()); liquibase.setRollbackFile(properties.getRollbackFile()); return new CustomSpringLiquibase(liquibase); } }
2. 强制JPA EntityManagerFactory依赖Liquibase
确保Liquibase先完成数据库初始化,再创建EntityManagerFactory。可以通过两种方式实现:
方式一:自定义EntityManagerFactory并注入Liquibase
添加JPA配置Bean,显式依赖liquibase Bean:@Configuration @EnableJpaRepositories(basePackages = "your.repository.package") @EntityScan(basePackages = "your.entity.package") public class JpaConfig { @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory( EntityManagerFactoryBuilder builder, DataSource dataSource, @Qualifier("liquibase") CustomSpringLiquibase liquibase) { // 注入liquibase以建立依赖关系,确保Liquibase先执行 return builder .dataSource(dataSource) .packages("your.entity.package") .build(); } }方式二:给WebSecurityConfig添加@DependsOn
让Security配置类等待Liquibase初始化完成:@Configuration @DependsOn("liquibase") // 确保Liquibase先初始化 public class WebSecurityConfig { // 原有配置代码 }
3. 延迟Security层对Repository的依赖
给SecurityService中UserRepository的Setter注入添加@Lazy,延迟Repository的初始化时机,避免在EntityManagerFactory就绪前触发:
@Autowired @Lazy public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; }
4. 验证循环依赖配置的生效性
确认application.properties中的配置正确,Spring Boot 3.x中该配置仍生效,但需确保没有其他配置覆盖它:
spring.main.allow-circular-references=true
关键原理说明
Spring Boot 2.x到3.x的数据库初始化流程有微调,Liquibase的默认初始化优先级与JPA的EntityManagerFactory创建逻辑发生了变化。你的依赖链显示EntityManagerFactory间接依赖Liquibase,若Liquibase初始化滞后,会导致Repository无法获取到EntityManagerFactory实例。通过调整依赖顺序或延迟初始化,可打破这个初始化死锁。
内容的提问来源于stack exchange,提问作者Subodh Joshi

