0

0

Spring Boot 多模块集成中的循环依赖问题与解决方案

聖光之護

聖光之護

发布时间:2025-12-27 13:18:09

|

282人浏览过

|

来源于php中文网

原创

Spring Boot 多模块集成中的循环依赖问题与解决方案

本文详解 spring boot 应用间(如 jmix 主应用集成独立批处理模块)因包扫描冲突与 bean 创建顺序不当引发的 `beancurrentlyincreationexception` 循环引用错误,并提供基于 `@lazy`、精准包扫描、配置分离等可落地的工程化解决策略。

在将独立的 Spring Boot 批处理模块(如 com.publicismedia.uniquebatchjava)集成至 Jmix 主应用时,常见错误 Requested bean is currently in creation: Is there an unresolvable circular reference? 并非源于 Maven 依赖本身,而是由 Spring 容器在初始化阶段因隐式依赖链闭环导致的 Bean 创建死锁。从堆可见关键路径:
OAuth2AuthorizationServerConfiguration → tokenStore → stellantisroiApplication → batchExecuter → batchConfigRepository → entityManager → entityManagerFactory → jmix_Liquibase → dataSource
而 dataSource 又被 jmix_Liquibase 和 JPA 的 entityManagerFactory 同时依赖——若二者均尝试在初始化早期强依赖 dataSource,且 dataSource 自身配置又间接依赖其他尚未就绪的 Bean(如 Liquibase 或 Security 相关组件),即构成典型的 A → B → A 型循环依赖

✅ 根本解决策略(按推荐优先级排序)

1. 精准控制自动配置与包扫描范围

避免 @SpringBootApplication(scanBasePackages = {...}) 过度扫描引发意外 Bean 注入。应严格隔离关注域:

@SpringBootApplication(
    scanBasePackages = {
        "io.jmix.example",           // Jmix 主应用包
        "com.publicismedia.uniquebatchjava.config"  // 仅扫描批处理的配置类,非全包
    }
)
@EnableJmixDataRepositories(basePackages = "io.jmix.example.repository") // 明确限定 Jmix 仓库范围
@EnableJpaRepositories(
    basePackages = "com.publicismedia.uniquebatchjava.repository",
    entityManagerFactoryRef = "uniqueBatchEntityManagerFactory", // 指向专用 EMF
    transactionManagerRef = "uniqueBatchTransactionManager"
)
public class JmixApplication {
    public static void main(String[] args) {
        SpringApplication.run(JmixApplication.class, args);
    }
}
⚠️ 关键点:绝不使用空 basePackages = {}(@EnableJmixDataRepositories(basePackages = {}) 实际无效,可能触发默认扫描),而应显式指定 Jmix 自己的包;同时为批处理模块声明独立的 EntityManagerFactory 和事务管理器,彻底解耦数据源生命周期。

2. 对高风险依赖字段添加 @Lazy

当无法重构依赖关系时,在非核心初始化路径上使用延迟加载打破循环:

@Service
public class BatchExecutor {

    // 避免在构造/字段注入阶段强依赖,改用 @Lazy + 接口注入
    @Lazy
    @Autowired
    private BatchConfigRepository batchConfigRepository; // 此 Repository 依赖 EntityManager → dataSource

    // 或更安全:通过 ObjectProvider 延迟获取
    @Autowired
    private ObjectProvider batchConfigRepositoryProvider;

    public void execute() {
        BatchConfigRepository repo = batchConfigRepositoryProvider.getObject();
        // ... 业务逻辑
    }
}

3. 分离数据源与 Liquibase 配置

确保批处理模块不共享主应用的 dataSource 和 Liquibase 配置。在 application.yml 中明确隔离:

薏米AI
薏米AI

YMI.AI-快捷、高效的人工智能创作平台

下载
# 主应用数据源(Jmix 默认)
spring:
  datasource:
    url: jdbc:h2:mem:jmixdb
    # ... 其他配置

# 批处理专用数据源(独立)
unique-batch:
  datasource:
    url: jdbc:postgresql://localhost:5432/batchdb
    username: batchuser
    password: batchpass

# 禁用批处理模块的 Liquibase 自动配置(避免与 jmix_Liquibase 冲突)
spring:
  autoconfigure:
    exclude:
      - io.jmix.autoconfigure.data.JmixLiquibaseAutoConfiguration
      - org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration

并在 Java Config 中定义专属 Bean:

@Configuration
public class UniqueBatchDataSourceConfig {

    @Bean
    @ConfigurationProperties("unique-batch.datasource")
    public DataSource uniqueBatchDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean uniqueBatchEntityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("uniqueBatchDataSource") DataSource dataSource) {
        return builder
                .dataSource(dataSource)
                .packages("com.publicismedia.uniquebatchjava.entity")
                .persistenceUnit("unique-batch-pu")
                .build();
    }
}

? 总结与最佳实践

  • 循环依赖本质是设计信号:优先审视 batchExecuter → batchConfigRepository → dataSource 链路是否合理——批处理服务是否必须在应用启动时就持有 Repository?考虑改为按需初始化(@Scope("prototype") 或 ObjectProvider)。
  • 永远显式而非隐式:禁用全局 scanBasePackages,改用 @Import 导入模块配置类,或通过 @ConditionalOnClass 控制自动配置生效条件。
  • 验证依赖图:启用 --debug 启动参数,查看 CONDITIONS EVALUATION REPORT 和 BEAN DEPENDENCIES REPORT,定位真实循环节点。
  • 模块化优于集成:长期建议将批处理改造为独立服务(HTTP API 或消息队列触发),通过契约交互,从根本上规避 Spring 上下文耦合。

遵循以上方法,即可安全、稳定地将 Spring Boot 批处理模块嵌入 Jmix 等复合框架中,既复用业务逻辑,又保障容器健康。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

674

2023.06.15

java流程控制语句有哪些
java流程控制语句有哪些

java流程控制语句:1、if语句;2、if-else语句;3、switch语句;4、while循环;5、do-while循环;6、for循环;7、foreach循环;8、break语句;9、continue语句;10、return语句。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

455

2024.02.23

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

722

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

727

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

394

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

441

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

428

2023.08.02

ip地址修改教程大全
ip地址修改教程大全

本专题整合了ip地址修改教程大全,阅读下面的文章自行寻找合适的解决教程。

27

2025.12.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2万人学习

C# 教程
C# 教程

共94课时 | 5.4万人学习

Java 教程
Java 教程

共578课时 | 38.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号