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

Spring Modulith应用中事件的放置位置:模块内还是共享模块?

Spring Modulith事件存放方案对比与建议

在Spring Modulith中处理事件时,两种存放方案各有优劣,核心要围绕模块自治性和长期可维护性来权衡:

方案一:事件放在对应模块内(推荐)

目录结构示例:

- com.example
  |- product
     |- application
     |- domain
     |- events
        |- Product.java
        |- ProductEvent.java
        |- package-info.java
     |- spi
     |- web
  |- order
     ...

优势:

  • 贴合模块化设计原则:事件是模块业务逻辑的自然产物(比如ProductEvent必然是Product模块内业务变化触发的),放在模块内让代码职责更清晰,维护时能直接在模块内找到事件的定义、触发逻辑,不用跨模块跳转。
  • 避免shared模块膨胀:shared模块很容易沦为“万能垃圾桶”,什么都往里塞,最后变成难以维护的大杂烩。把事件留在各自模块,能让shared模块只承担真正跨模块共享的基础能力(比如通用工具类、基础DTO)。
  • 适配Spring Modulith原生机制:Spring Modulith本身强调模块自治,通过@ApplicationModule和@Exported可以精准控制模块对外暴露的事件,其他模块通过订阅机制消费事件,既实现松耦合,又保持模块边界清晰。

方案二:事件放在shared模块

目录结构示例:

- com.example
  |- product
     |- application
     |- domain
     |- spi
     |- web
     ...
  |- shared
     |- events
        |- product
           |- Product.java
           |- ProductEvent.java          
        |- order
           |- Order.java
           |- OrderEvent.java   
  ...

表面优势:

  • 模块之间不直接依赖,都依赖shared模块,看起来实现了“完全解耦”;若未来要拆分微服务,事件定义已经在共享模块,不用调整依赖关系。

实际问题:

  • 破坏模块自治:事件是模块业务的一部分,放在shared模块意味着模块的业务变更需要修改shared模块(比如新增事件、修改事件字段),违反了“模块对自己的产出负责”的原则,增加跨模块修改成本,还容易引发代码冲突。
  • 维护成本高:所有模块的事件堆在shared模块,随着业务发展,shared会越来越臃肿,难以梳理每个事件的业务归属和触发逻辑,排查问题时要跨多个模块找事件源头,效率极低。

最终建议

优先选择将事件放在对应模块内,这更符合Spring Modulith的设计哲学。如果担心未来拆分微服务,可以通过以下方式优化:

  • 在模块的events包上添加@Exported注解,明确对外暴露的事件,其他模块通过Spring Modulith的订阅机制消费,无需依赖模块的其他部分。
  • 事件类保持简洁,只包含必要的业务数据,避免依赖模块内的复杂对象,这样即使未来拆分,事件也能轻松迁移到独立的API模块(而非现在就提前塞到shared里)。
  • 仅将真正跨模块共享的基础事件结构(比如通用DomainEvent基类)放在shared模块,具体业务事件仍留在各自模块。

内容的提问来源于stack exchange,提问作者energize-cactus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 10:28:20