主数据平台的架构选择一直是团队早期最纠结的决策之一——上微服务怕运维成本爆炸,留单体怕后期拆分痛苦。MDP 1.2.0 给了一个务实的答案:同一套业务代码,不改逻辑,通过配置和构建方式决定最终跑成单体还是微服务。与此同时,这版把 Spring Boot、Dubbo、Nacos 等核心依赖全线拉到最新,底座安全性和兼容性同步刷新。
"一套代码两种架构"怎么做到的
核心思路并不神秘:模块边界提前划定,通信方式延迟决定。
业务代码只面向接口调用,不直接依赖具体实现。运行时由框架根据当前架构模式(单体 or 微服务)决定调用走本地方法引用还是远程 RPC。这要求:
- 每个业务模块对外暴露的 API 是纯接口(无实现类依赖)。
- 模块间调用统一走接口注入,Spring 容器在单体模式下注入本地 Bean,微服务模式下注入 Dubbo 代理。
- 配置文件和构建脚本控制哪些模块打进同一个 JAR、哪些独立部署。
这意味着团队可以在项目初期用单体模式快速迭代,业务稳定后再逐模块拆出独立服务,整个过程业务代码零改动。
依赖全线升级的关键变化
1.2.0 的依赖升级不是例行公事,几项变动直接影响开发体验和运行安全:
| 依赖 | 旧版本 | 新版本 | 实际影响 |
|---|---|---|---|
| Spring Boot | — | 3.5.14 | Jakarta EE 命名空间全面生效,老代码中 javax.* 导入必须替换 |
| Spring Cloud | — | 2025.0.2 | 与 Boot 3.5.x 对齐,服务发现与配置中心 API 有小幅度变更 |
| Nacos | — | 3.2.1 | 配置中心鉴权默认开启,匿名访问不再放行 |
| Dubbo | — | 3.3.6 | Triple 协议性能优化,支持 gRPC 风格流式调用 |
| Sa-Token | — | 1.45.0 | 权限校验注解扩展,支持更细粒度的路由级拦截 |
| MyBatis-Flex | — | 升级 | 查询构建器链式 API 增强,多表关联更简洁 |
最值得注意的三个点:
- Nacos 3.x 鉴权强制化:之前很多团队直接裸跑 Nacos,2.x 版本默认不鉴权,3.2.1 改了这一行为。升级后必须配置
token和identity,否则服务注册直接失败。 - Dubbo 3.3.x Triple 协议:如果之前用的是 dubbo 协议,升级后建议逐步迁移到 triple,后者兼容 gRPC、支持流式,且不再依赖 Hessian 序列化,安全面更干净。
- Spring Boot 3.5.x 的 Jakarta 迁移:这是不可跳过的一步,所有
javax.servlet、javax.persistence必须改成jakarta.servlet、jakarta.persistence,否则编译直接报错。
实战:用 MDP 1.2.0 切换架构模式
下面用一个简化的项目结构演示如何通过配置切换单体和微服务两种运行模式。
项目模块划分
mdp-demo/
├── mdp-api/ # 对外接口定义(纯接口 + DTO)
├── mdp-user/ # 用户模块实现
├── mdp-org/ # 组织模块实现
├── mdp-gateway/ # 网关(微服务模式才需要)
├── mdp-app/ # 单体启动器(把所有模块打进一个 JAR)
└── pom.xml
单体模式:所有模块合体启动
mdp-app/pom.xml 把所有实现模块作为依赖引入:
<dependencies>
<dependency>
<groupId>com.mdp</groupId>
<artifactId>mdp-user</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.mdp</groupId>
<artifactId>mdp-org</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
单体模式下的 Spring Boot 启动类:
package com.mdp.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = {"com.mdp.user", "com.mdp.org"})
public class MonolithApplication {
public static void main(String[] args) {
SpringApplication.run(MonolithApplication.class, args);
}
}
单体模式下,mdp-user 调用 mdp-org 的接口,Spring 直接注入本地实现 Bean,零网络开销。
微服务模式:模块独立部署 + Dubbo RPC
每个模块独立打包,通过 Dubbo 暴露服务。以 mdp-user 为例,启动类变为:
package com.mdp.user;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
微服务模式的核心配置 application.yml:
spring:
application:
name: mdp-user
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: mdp-dev
config:
server-addr: 127.0.0.1:8848
namespace: mdp-dev
# Nacos 3.x 必须配置鉴权
token: ${NACOS_AUTH_TOKEN}
identity-key: ${NACOS_IDENTITY_KEY}
identity-value: ${NACOS_IDENTITY_VALUE}
dubbo:
protocol:
name: triple # 推荐使用 triple 协议
port: 20880
registry:
address: nacos://127.0.0.1:8848?namespace=mdp-dev
scan:
base-packages: com.mdp.user.service
服务实现类加上 Dubbo 注解即对外暴露:
package com.mdp.user.service;
import com.mdp.api.OrgService;
import com.mdp.api.UserService;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
@DubboService
public class UserServiceImpl implements UserService {
// 微服务模式下注入远程代理;单体模式下 Spring 注入本地 Bean
@DubboReference(check = false)
private OrgService orgService;
@Override
public String getUserWithOrg(Long userId) {
String userName = "user-" + userId;
String orgName = orgService.getOrgName(userId);
return userName + "@" + orgName;
}
}
关键点在于 @DubboReference(check = false)——check = false 让单体模式下启动不校验远程服务是否存在,Spring 容器会优先注入本地同类型 Bean,Dubbo 代理只在微服务模式下生效。
构建切换:Maven Profile 控制打包范围
在根 pom.xml 中用 Profile 决定构建产物:
<profiles>
<profile>
<id>monolith</id>
<modules>
<module>mdp-api</module>
<module>mdp-user</module>
<module>mdp-org</module>
<module>mdp-app</module>
</modules>
</profile>
<profile>
<id>microservice</id>
<modules>
<module>mdp-api</module>
<module>mdp-user</module>
<module>mdp-org</module>
<module>mdp-gateway</module>
</modules>
</profile>
</profiles>
构建命令:
# 单体模式打包
mvn clean package -P monolith
# 微服务模式打包(每个模块独立 JAR)
mvn clean package -P microservice
升级到 1.2.0 的实操检查清单
- Jakarta 命名空间迁移:全局搜索
javax.servlet、javax.persistence、javax.validation,批量替换为jakarta.*对应包名。IDE 的 Find & Replace 即可完成,但务必逐文件确认,部分第三方库可能仍依赖旧命名空间,需要同步升级。 - Nacos 鉴权配置:在所有环境的 Nacos 连接配置中补上
token、identity-key、identity-value。建议通过环境变量注入,不要硬编码到配置文件。 - Dubbo 协议迁移:如果当前用的是
dubbo协议(基于 Hessian),先在配置中同时启用dubbo和triple双协议并行,灰度验证后再移除旧协议。 - Sa-Token 路由拦截:1.45.0 支持路由级注解,检查现有拦截器配置,把过于宽泛的全局拦截逐步收窄到具体路由。
- MyBatis-Flex 查询重构:新版本链式 API 更简洁,多表关联不再需要手写大量 SQL 拼接,但旧代码的
QueryWrapper风格仍兼容,不必一次性全改。
一句话总结:MDP 1.2.0 的"一套代码两种架构"不是概念噱头,而是通过接口隔离 + Dubbo 代理 + Maven Profile 三层机制落地的工程方案。依赖升级是硬门槛,Jakarta 迁移和 Nacos 鉴权必须先做;架构切换是软收益,团队可以在单体模式下跑通业务,再择机拆分,不必在项目第一天就赌微服务。