You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot从2.7.2升级到3.1.5后循环依赖问题求助

Spring Boot 3.1.5升级后循环依赖与EntityManagerFactory初始化问题排查

问题核心

升级后出现循环依赖链: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 21:36:34