一个 Spring Boot 项目,为什么要拆成 bootstrap、web、business、foundation、components、iot?

Spring Boot 项目时,很多人都会做模块拆分。

但模块拆分这件事,真正难的从来不是"拆几个模块",而是"为什么这样拆"。

有些项目看起来模块很多,继续往下看却会发现:controller 里写业务,service 里拼协议,公共能力散落在各处,最后虽然工程被拆开了,边界却并没有真正清楚。

ems4j 在项目级分层上想解决的,不是"把模块拆得更多",而是另一件更实际的事情:

把变化和复杂度关在合适的位置。

这篇文章不展开单个模块内部实现,只从项目级架构出发,聊聊 ems4j 为什么要拆成 bootstrap / web / business / foundation / components / iot 这几层。

1. 为什么很多项目分了层,最后还是会乱

很多项目的问题,并不是没有分层,而是分层停留在目录层面。

比如一个常见情况是:

  • web 层不只是接接口,还开始承载业务判断
  • 业务模块里混入用户、组织、空间这类基础能力
  • 通用组件里又写进了业务语义
  • 设备接入和业务处理搅在一起

这样一来,工程虽然有了多个模块,但模块之间的职责并没有真正收住。最后的结果通常是:

  • 某个功能一改,要同时改好几层
  • 公共能力无法稳定复用
  • 业务和技术实现互相污染
  • 读代码时很难快速判断"这段逻辑应该属于哪一层"

所以我理解的分层设计,不是"多建几个 Maven 模块",而是先回答一个问题:

这段职责,究竟应该放在哪一层,才不会把后续变化扩散出去?

ems4j 的项目级拆分,就是围绕这个问题做的。

2. ems4j 的项目级分层,不是横向切包,而是纵向划边界

从整体看,ems4j 的主干大致可以理解成这样:

  • ems-bootstrap:应用启动入口
  • ems-web:HTTP 接口层
  • ems-business:核心业务层
  • ems-foundation:跨业务共享的基础能力层
  • ems-components:可复用的通用技术组件层
  • ems-iot:独立的设备接入与协议平台

用一张简化的 ASCII 图看,整体结构大致是这样:

sql 复制代码
+----------------------+
|    ems-bootstrap     |
|   应用启动 / 装配    |
+----------+-----------+
           |
           v
+----------------------+
|       ems-web        |
|   HTTP 接口 / 视图   |
+----------+-----------+
           |
           v
+--------------------------------------------------+
|                   ems-business                   |
| device / account / billing / order / lease ...  |
+----------+----------------------+----------------+
           |                      |
           v                      v
+----------------------+   +----------------------+
|    ems-foundation    |   |    ems-components    |
| 用户/组织/空间/集成  |   | 锁/数据源/上下文等   |
+----------------------+   +----------------------+

如果只看名字,这几个模块很普通。

但这套拆分真正重要的地方,不在于"模块名称是什么",而在于每一层都在刻意回答一个问题:

  • 哪些逻辑属于应用入口
  • 哪些逻辑属于接口表达
  • 哪些逻辑属于核心业务
  • 哪些逻辑属于基础域能力
  • 哪些逻辑属于技术基础设施
  • 哪些逻辑应该被隔离在设备平台内部

3. bootstrap:只负责启动和装配,不承载具体业务

ems-bootstrap 在这套结构里是最上层入口。

它的职责很克制:负责应用启动、模块装配、配置加载和整体运行入口,而不是去承载某个具体业务模块的实现。

这样做的价值很直接。

如果启动入口里直接堆满业务逻辑,那么应用装配和业务处理就会耦合在一起。后面你想拆服务、换部署方式、补外部依赖时,入口层就会越来越重。

bootstrap 单独拿出来,至少可以保证一件事:

应用怎么启动是一回事,业务怎么实现是另一回事。

4. web:只表达接口,不承载核心业务

ems-web 的定位也很明确,就是 HTTP 接口层。

它负责的事情包括:

  • 接收前端请求
  • 做接口层参数组织
  • 返回前端需要的视图对象
  • 处理权限、路由和接口层表达

但它不应该直接承载核心业务。

这一点在很多项目里最容易失控。因为接口层最靠近需求,一旦赶进度,很多业务判断会自然地写进 controller 或者 biz 编排里。短期看好像更快,长期看却会把业务边界打穿。

ems4j 这里强调的是:

接口层的价值,在于把请求翻译成系统能处理的输入,而不是替代业务层做判断。

所以 web 的存在,不是为了多加一层,而是为了把"接口表达"这件事从"业务实现"里剥离出来。

5. business:把账户、设备、计费、订单这些核心逻辑放在一起

如果说哪一层是系统主体,那一定是 ems-business

ems4j 里,核心业务被放在这里,主要包括:

  • device:设备档案与设备管理
  • account:账户信息、开户、销户
  • billing:计费、消费、账务处理
  • order:订单创建、支付回调、订单状态流转
  • lease:主体与空间租赁关系
  • plan:电价方案、尖峰平谷、预警方案
  • aggregation:跨业务读聚合与应用编排

把这些模块集中在 business 层的意义,是把"系统真正关心的业务问题"沉淀下来。

因为一个业务系统里,变化最频繁、最值得认真建模的,通常不是接口格式,也不是框架配置,而是账户、订单、计费、设备这些领域逻辑本身。

所以 business 这一层的存在,不只是为了分类,更是为了明确:

系统的重心到底在哪里。

6. foundation:基础能力不属于某个业务模块

很多项目刚开始规模不大时,用户、组织、空间、通知、系统配置这些能力,常常会被顺手放进某个业务模块里。

但当业务越来越多时,这种放法会很快变成问题。

因为这些能力本身并不属于某个单独业务域,它们更像是整个系统都要共享的基础服务。比如:

  • 用户认证、角色、权限
  • 组织与多租户能力
  • 空间与区域管理
  • 系统配置
  • 平台集成能力
  • 通知能力

也就是说,foundation 解决的是:

哪些能力应该被多个业务域共同依赖,但又不该反过来依赖具体业务。

7. components:通用技术能力应该被抽出来,但不要带业务语义

ems-componentsems-foundation 很容易被混淆。

看起来两者都像"公共模块",但它们解决的问题并不一样。

foundation 偏业务共享能力,components 偏纯技术组件。

ems4j 里,components 里放的是这类内容:

  • 数据源能力
  • 锁能力
  • 上下文能力
  • Redis 等基础组件
  • 翻译组件

这些能力的共同点是:它们可以被很多地方复用,但本身不应该携带具体业务语义。

如果把这类技术组件直接和账户、设备、订单这些业务概念混在一起,后面复用边界就会很难看清。

反过来,如果把业务判断写进组件层,又会让组件失去"通用"的意义。

所以 components 这一层最核心的约束其实是:

只做通用技术能力,不承载具体业务含义。

8. iot:设备接入平台应该独立,而不是塞进业务层

ems4j 里还有一个很关键的拆分,就是把 ems-iot 单独拉出来。

这是很多类似系统和普通后台项目真正不一样的地方。

如果设备接入、协议解析、命令路由这些内容直接塞进业务层,会发生什么?

很简单,业务模块会一边处理账户、订单、计费,一边还要理解设备协议、网络通信、命令格式、上下行事件,最后整个系统会同时承载两套完全不同层次的复杂度。

ems-iot 单独存在之后,边界就清楚很多了:

  • 业务系统负责表达"我要什么设备能力"
  • IoT 平台负责处理"设备到底怎么通信、怎么解析、怎么下发"

这类拆分的价值,不只是模块更清楚,更重要的是:

设备侧复杂度不会直接污染业务层。

9. 这套分层真正解决了什么问题

如果只从模块图看,这套结构看起来像是常规的多模块拆分。

但它真正解决的问题,不在图上,而在后续演进里。

我觉得至少解决了 4 件事:

  1. 接口变化不会直接冲击业务实现
    web 负责接口表达,业务层保持稳定。
  2. 基础能力不会散落到各个业务模块
    foundation 收住共享能力,避免重复建设。
  3. 通用技术组件不会和业务语义混在一起
    components 保持技术中立,复用边界更清楚。
  4. 设备接入复杂度不会直接扩散到业务层
    iot 独立存在,业务和协议分开演进。

所以这套分层的核心价值,不是"工程更好看",而是:

系统在继续增长时,复杂度不会无序扩散。

10. 最后

我一直觉得,架构分层设计最容易被误解成"模块越多越高级"。

但真正有价值的分层,不是多,而是准。

不是把东西拆碎,而是把不同性质的职责放到合适的位置。

ems4j 这套项目级分层,未必是唯一答案,但它至少在试图解决一个很现实的问题:

当系统同时面对后台管理、业务建模、计费结算、设备接入和平台集成时,怎么让每一层都只处理自己该处理的事。

如果你也在做 Spring Boot 多模块项目,或者正在思考业务系统和设备平台该怎么拆,ems4j 这套结构应该会有一些参考价值。

相关推荐
Lear2 小时前
【SpringBoot】 前后端参数命名踩坑记录:小驼峰变下划线导致接收不到参数
后端
希望永不加班2 小时前
SpringBoot 配置 HTTPS(自签名证书+正式证书)
java·spring boot·后端·spring·https
小马爱打代码2 小时前
Spring Boot内嵌容器深度解析:Tomcat是如何被启动的?
spring boot·后端·tomcat
小江的记录本2 小时前
【反射】Java反射 全方位知识体系(附 应用场景 + 《八股文常考面试题》)
java·开发语言·前端·后端·python·spring·面试
孟陬2 小时前
国外技术周刊 #4:这38条阅读法则改变了我的人生、男人似乎只追求四件事……
前端·人工智能·后端
没有bug.的程序员2 小时前
100%采样率引发的全线熔断:Spring Boot 链路追踪的性能绞杀与物理级调优
java·spring boot·后端·生产·熔断·调优·链路追踪
无籽西瓜a2 小时前
Linux 文件权限与 chmod 详解
linux·服务器·后端
thulium_3 小时前
Rust 编译错误:link.exe 未找到
开发语言·后端·rust
SimonKing3 小时前
IntelliJ IDEA 配置与插件全部迁移到其他盘,彻底释放C盘空间
java·后端·程序员