告别“大泥球”:我在 Spring Boot 单体架构中实践的模块化隔离

前言:为什么我没选微服务

经常有同行问我:"你们的网优系统业务这么复杂,为什么不拆微服务?"

我的回答很直接:因为我们的核心痛点不是"并发扩展",而是"逻辑闭环"。

电信网络优化领域,一个"天线接反"的判断,可能同时涉及告警数据、MR(测量报告)采样、工参地理信息以及历史性能趋势。如果把这些强行拆成四个微服务,光是处理分布式事务和链路追踪,就能把团队拖垮。

但这不代表我们可以容忍代码耦合。在 通信网络优化与分析平台 的 性能 子系统中,我坚持推行一种**"物理隔离、逻辑内聚"**的单体模块化策略。今天,我想抛开那些高大上的理论,聊聊我们是怎么在 Java 生态上,把代码治理得井井有条的。


一、 拒绝"水平分层"的陷阱

传统的 MVC 教程喜欢教你:所有 Controller 放一起,所有 Service 放一起。结果就是,controllers 文件夹里塞了 50 个文件,你想找个"PCI 规划"的代码,得在一堆 Alarm,User、Log 控制器里翻半天。

通信网络优化与分析平台 中,我强制要求按业务域垂直切分(Package by Feature)

1. 目录结构的重构

我们不再使用扁平的包结构,而是采用垂直切片:

rust 复制代码
cn.starlinkcloud.crystal.noap.perf
├── antenna       // 天线调整模块
│   ├── controller
│   │   └── AntennaFeederAdjController.java
│   ├── service
│   │   ├── AntennaService.java
│   │   └── impl
│   │       └── AntennaServiceImpl.java
│   ├── repository
│   │   └── AntennaRepository.java
│   └── model
│       ├── entity
│       │   └── AntennaReversedError.java
│       └── dto
│           └── AntennaQueryDTO.java
├── pci           // PCI 规划模块
│   ├── controller
│   │   └── PCIController.java
│   ├── service
│   │   └── ...
│   └── ...
└── common        // 通用能力下沉
    ├── excel
    │   └── ExcelExportHelper.java
    └── gis
        └── GridMergeHelper.java

原则 :一个包(Package),就是一个完整业务场景的边界。它不应该去依赖其他无关业务的 Package。如果 pci 模块需要用到告警数据,它注入的是 IAlarmService 接口,而不是直接去查告警表。

2. 前端资源的模块化

在后端垂直切分的同时,前端(Vue/React)也采用类似的模块化结构:

  • src/views/antenna/index.vue:天线调整页面组件。
  • src/api/antenna.js:专门服务于天线模块的 Axios 请求封装。

效果 :即使两个模块里都有 initTable() 函数,只要它们在不同的 Vue 组件或 JS 模块中,就不会打架。


二、 实体类不是数据库表的奴隶:DTO 与 Entity 分离

在 JPA/Hibernate 时代,很多人习惯搞一个巨大的 @Entity 类,把所有字段都塞进去,并直接返回给前端。

我反对这种做法。在网优领域,上下文不同,模型不同

1. 细分的领域对象

  • Entity 层:AlarmL4G.java对应数据库表,使用 JPA 注解。
  • DTO 层AlarmListDTO 只包含列表页需要的几个关键字段(小区名、告警码、时间)。
  • VO 层AntennaReversedErrorVO 是经过算法计算后的"结果对象",用于前端展示。

架构师视角 :使用 MapStruct 进行对象转换,避免手动写 getter/setter。当你在代码里看到PCICheckRule.java时,你应该意识到这是一条规则,而不是一行 SQL 记录。


三、 接口隔离与依赖注入:Spring 的核心灵魂

虽然现在是单体,但我要求所有 Service 必须定义接口,并使用 @Autowired 或构造函数注入。

为什么?

  1. 单元测试能跑通 :在测试HealthDiagnosisController时,我可以 @MockBeanIHealthDiagnosisService,不用启动数据库,测试速度从分钟级降到秒级。
  2. 随时准备"剥离" :如果哪天老板说,"这个 PCI 算法太耗 CPU,我们要把它独立成一个 Python 微服务",我只需要重写IPCIService的实现类,让它去调 RestTemplate/WebClient,而 Controller 层的代码一行都不用改

这就是依赖倒置带来的底气。


四、 通用能力下沉:别重复造轮子

在每个模块里写 Excel 导出?别逗了。

我把所有跨模块的通用逻辑,全部扔进 common 模块或 Starter:

1. 重型计算的下沉:GridMergeHelper

电信网优系统离不开 GIS。我们将栅格合并算法封装在 common-gis 模块中:

  • 并行计算 :利用 Java 8 ParallelStreamCompletableFuture 优化多点聚合。
  • 空间索引:引入 JTS (Java Topology Suite) 库处理地理围栏和点位落入计算。

2. IO 密集型操作的封装:ExcelExportUnity

  • 流式写入 :使用 EasyExcel (Alibaba) ,避免 OOM。
  • 注解驱动 :通过 @ExcelProperty 定义列头,实现声明式导出。

使用场景: 无论是 AlarmStatisticsController 还是 VoltePoorQualityCellAnalysisController,只需调用同一行代码:

bash 复制代码
return ExcelExportHelper.export(response, dataList, "告警统计表.xlsx");

五、 多主题支持:前端工程化的胜利

Spring Boot 后端,我们不再处理 CSS 文件。多主题支持完全交给前端工程化(Webpack/Vite)处理。

  • CSS Variables:使用 CSS 变量定义颜色主题。
  • 动态加载 :根据用户配置,在前端入口文件动态引入 theme-blue.csstheme-red.css

后端职责:只提供用户偏好配置的 API 接口,彻底解耦表现层与业务层。


六、 给维护者的真心话

如果你正在接手或维护类似 CNOAP 的 Spring Boot 系统,我有三条建议:

  1. 严守包边界 :不要为了方便,在 AntennaController 里直接 @Autowired 一个 PCIRepository。请走 Service 接口。一旦开了这个口子,模块化就名存实亡。
  2. 统一异常处理 :使用 @RestControllerAdvice 全局捕获异常,返回统一的 JSON 格式,避免每个 Controller 都写 try-catch。
  3. 关注 Common 模块 :随着系统运行,Common 模块容易变成垃圾堆。定期审查,把那些只被一个模块使用的"通用"代码,移回它所属的业务模块。真正的通用,是被三个以上模块依赖。

结语

架构没有银弹。微服务很好,但对于强逻辑关联、重算法计算的网优系统,模块化的 Spring Boot 单体依然是性价比最高的选择。

我们不追求技术的时髦,我们追求的是:当业务人员问"为什么这个小区 PCI 冲突没算出来"时,我们能要在 5 分钟内定位到代码,而不是在 5 个微服务的日志里迷路。

版权声明:本文为原创文章,转载请注明出处。商业转载请联系作者获得授权。

作者简介:系统架构师,专注于电信大数据平台架构设计与运维。目前负责日均处理2亿条消息的ucp平台,擅长分布式系统设计、消息中间件运维和高可用架构。

相关推荐
长大19881 小时前
Python 新手最容易踩的 10 个语法坑
后端
二月龙1 小时前
Python 迭代器与生成器精讲:大幅降低内存占用
后端
AINative软件工程2 小时前
Tool Schema 写得好,模型少出错:5 个工程师必知的设计原则
后端·openai
AINative软件工程2 小时前
AI 写的代码,Review 要怎么改?我们团队的 15 条 PR 检查清单
后端·openai
武子康2 小时前
Java-21 深入浅出 MyBatis 手写ORM框架2 手写Resources、MappedStatment、XMLBuilder等
java·后端
techdashen2 小时前
在 Fly.io 上使用 Rust 构建远程开发环境:从 Tokio 到 eBPF
开发语言·后端·rust
摇滚侠3 小时前
Spring 零基础入门到进阶 面向切面 AOP 52-60
java·后端·spring
雪隐3 小时前
AI股票小助手07-TA-Lib 技术指标计算实战
人工智能·后端
掘金者阿豪3 小时前
一本书读懂微积分!
后端