单体拆微服务,这 7 个坑你踩过几个? 接手了一套从单体架构拆分为微服务的 Spring Cloud Alibaba 项目。9 个服务,Spring Boot 3.3.5,集齐了 Nacos、Gateway、Sentinel、RocketMQ、ShardingSphere、Elasticsearch 全家桶——看 POM 文件像一份微服务教科书。
实际跑起来就发现问题了:项目虽然拆成了 9 个模块,但在架构思维上仍然是个单体。 用了微服务的壳,没改掉单体时代的坏习惯。一顿排查下来,发现了 7 个典型错误。
错误一:全量包扫描——每个服务都在扫整个宇宙 第一个映入眼帘的就是各个 Application 类上的注解:
@ComponentScan(basePackages = "cn.net.mall") 9 个服务里有好几个直接扫整个项目包树。这意味着什么? mall-pay 启动的时候,Spring 会去扫描 mall-common 下的所有类,包括 cn.net.mall.util.RedisUtil 。而 RedisUtil 又依赖 StringRedisTemplate ,这个类来自 spring-boot-starter-data-redis ,偏偏 mall-pay 的 POM 里没加这个依赖。
mall-pay 启动 → 扫描 cn.net.mall → 发现 RedisUtil → 尝试创建 → StringRedisTemplate 不在 classpath → ClassNotFoundException → 启动失败 flowchart LR subgraph SCAN["全量扫描 `cn.net.mall `"] PAY["mall-pay\n@ComponentScan"] COMMON["mall-common\nRedisUtil ← 依赖 → StringRedisTemplate"] end subgraph CLASSPATH["pay 的 classpath"] DEPS["mall-common.jar\n(但有 optional=true)"] MISSING["❌ StringRedisTemplate 不在"] end PAY -->|"扫描到"| COMMON COMMON -.->|"尝试创建 bean"| MISSING MISSING -->|"ClassNotFoundException"| CRASH["启动崩溃"] classDef process fill:#1e1e24,stroke:#6b7280,stroke-width:2px,color:#e5e7eb; classDef reject fill:#450a0a,stroke:#dc2626,stroke-width:2px,color:#fecaca; classDef highlight fill:#431407,stroke:#ea580c,stroke-width:2px,color:#fed7aa; class PAY,COMMON process; class MISSING,CRASH reject; class DEPS highlight; 更隐蔽的问题是:全量扫描让分仓库成为泡影。 微服务的核心理念之一就是独立开发、独立部署。如果每个服务都假设"所有模块在同一个 classpath 上",那一旦把服务拆到独立 Git 仓库,全量扫描就会漏掉其他服务的类——因为它根本不在 classpath 上。
...