Spring Boot多模块项目从六边形架构迁移至整洁架构的模块划分及领域层Service设计合理性咨询
看起来你已经对从六边形架构迁移到整洁架构做了不少功课,先给你点个赞!针对你的两个核心疑问——模块划分方式是否合理、领域层Service的设计思路是否正确,我结合Clean Architecture的核心原则和实际大型Spring Boot项目的经验来给你分析下:
一、按业务域拆分的模块划分方式完全合理,且能解决你当前的模块膨胀问题
你的模块划分思路完美契合了Clean Architecture「业务逻辑独立于技术实现」的核心原则,同时也符合DDD(领域驱动设计)中的限界上下文思想,完全是正确的方向:
1. 为什么比原来的六边形架构更优?
你之前的六边形架构按「端口/适配器类型」拆分出21个Inbounds、25个Outbounds模块,这种方式很容易导致模块数量爆炸——因为每个技术适配器(比如Spark、Postgis、REST)都要拆成独立模块,跨业务域的同类型适配器还要重复拆分。
而按**业务域(城市、企业、财税等)**聚合相关逻辑后,每个业务域内按整洁架构分层:
- domain层:作为核心,封装该业务域的所有纯业务逻辑(模型、仓库接口、用例、业务逻辑组件)
- infrastructure层:实现该业务域所有和外部技术相关的细节(Spark/Postgis仓库实现、DTO/实体、适配器)
- presentation层:负责该业务域的对外交互入口(REST控制器、Web UI控制器、DTO)
这种方式的优势非常明显:
- 内聚性极强:每个模块只关注自身业务域的逻辑,不会被其他业务域的技术细节干扰
- 维护成本低:每个业务域的团队可以独立维护自己的模块,不用关心其他业务域的实现
- 依赖关系清晰:完全符合整洁架构的依赖规则——内层(domain)不依赖外层(infrastructure/presentation),外层依赖内层的接口
2. 关于业务域拆分的补充建议
你提到这些业务域「过于庞大、关注点完全不同,无法合并」,这点我完全认同——强行把不同业务域的逻辑塞到同一个模块里,会导致模块变成“大泥球”,后续维护会非常痛苦。
可以给模块命名加上业务域前缀,比如cities-domain、cities-infrastructure、cities-presentation,这样在Maven/Gradle里管理依赖时会更清晰,也能避免模块名冲突。
二、领域层业务逻辑组件的设计思路正确,但要注意避免框架耦合
你提到的「在domain层实现仅包含接口调用和流程控制(if/while)的业务逻辑组件」,这完全符合Clean Architecture中领域层的职责定位,但有一个小细节需要调整:
1. 避免在domain层使用Spring的@Service注解
Clean Architecture要求领域层完全独立于任何框架,而@Service是Spring的框架注解——如果把它放到domain层,就会把Spring的耦合引入到最核心的业务逻辑层,违反了「独立于框架」的原则。
正确的做法是:
- 领域层的业务逻辑组件(可以叫Domain Service,或者直接用业务相关的命名,比如
CityRegistrationService)是纯Java类,不需要任何框架注解 - 它们的依赖(比如
CityRepository接口)通过构造函数注入,保持依赖的透明性 - 这些Domain Service的实例化,放到
infrastructure层的配置类里,用@Bean声明,把框架的依赖隔离到外层
2. Domain Service的职责边界
你说的「方法仅包含接口调用和if/while逻辑」是非常准确的——Domain Service的核心职责是:
- 封装跨实体的业务逻辑(比如“创建城市时需要同时校验企业关联规则”)
- 协调多个Repository的调用(比如“统计城市就业数据时,需要从就业仓库和企业仓库获取数据并聚合”)
- 处理业务流程的控制逻辑(比如“根据不同的城市等级,执行不同的税收计算流程”)
这些逻辑完全属于业务范畴,不涉及任何技术实现细节(比如数据库SQL、Spark算子、REST请求),这些细节都交给infrastructure层的适配器来实现。
而用例(Use Cases)则可以依赖Domain Service和Repository接口,把具体的业务场景逻辑串联起来,比如“创建城市的用例”会调用Domain Service的方法,再调用Repository的保存方法,整个用例逻辑也保持纯业务属性。
三、额外的实践小贴士
- 跨业务域交互:不同业务域之间只能通过对方
domain层的公共接口或领域事件来交互,绝对不能直接依赖其他业务域的infrastructure或presentation层,避免耦合扩散。 - 端口与适配器的映射:你原来六边形架构中的「Port(端口)」,对应整洁架构里
domain层的接口(比如Repository接口、用例的输入输出接口);「Adapter(适配器)」则对应infrastructure或presentation层的实现(比如PostgisRepositoryImpl、RestController),迁移时可以直接把原来的Port接口移到domain层,适配器移到对应外层。 - 测试效率提升:领域层的测试可以用纯JUnit编写,不需要启动Spring上下文——因为领域层是纯Java代码,测试速度极快,也能保证业务逻辑的正确性;
infrastructure和presentation层的测试再用Spring Test框架。
总结
你的模块划分思路完全正确,既解决了原来六边形架构的模块膨胀问题,又严格遵循了整洁架构的核心原则;领域层业务逻辑组件的设计思路也没问题,只需要调整一下框架注解的使用,就能让领域层保持纯业务、无框架耦合的状态。
如果在迁移过程中遇到具体的依赖管理或代码重构问题,随时可以再细化提问!




