跳转到内容

JeecgBoot 单体与微服务自由切换架构

JeecgBoot 单体与微服务自由切换架构

学习目标

通过本章学习,你将能够:

  • 理解 JeecgBoot 如何实现同一代码库的单体/微服务双模式切换
  • 掌握 API 层抽象隔离的设计模式
  • 了解微服务组件(Nacos、Gateway、Sentinel)的集成方案
  • 掌握切换机制对业务代码的零影响设计

项目实践

模块总览

切换核心:API 层双实现

切换的核心在于 jeecg-system-api 模块的双实现:

jeecg-system-api
├── jeecg-system-local-api # 单体模式:本地方法调用
│ └── ISysBaseAPI.java # 纯接口定义,无远程调用
└── jeecg-system-cloud-api # 微服务模式:Feign 远程调用
└── ISysBaseAPI.java # 同接口名,@FeignClient 注解标记

接口定义一致,实现方式不同

// local-api:纯接口,由 biz 模块实现
public interface ISysBaseAPI {
Result<?> addSysAnnouncement(SysAnnouncement announcement);
void sendSysAnnouncementPush(String message);
// ... 更多方法
}
// cloud-api:Feign 客户端,由调用方直接注入
@FeignClient("jeecg-system")
public interface ISysBaseAPI {
@PostMapping("/sys/api/addSysAnnouncement")
Result<?> addSysAnnouncement(@RequestBody SysAnnouncement announcement);
@PostMapping("/sys/api/sendSysAnnouncementPush")
void sendSysAnnouncementPush(@RequestParam String message);
// ... 同接口名,远程实现
}

切换方式:修改启动模块(jeecg-system-startjeecg-system-cloud-start)的 POM 依赖:

<!-- 单体模式 -->
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<artifactId>jeecg-system-local-api</artifactId>
</dependency>
<!-- 微服务模式 -->
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<artifactId>jeecg-system-cloud-api</artifactId>
</dependency>

业务代码无感知:业务模块(jeecg-system-bizjeecg-boot-module-airag)只依赖接口,不关心是本地调用还是远程调用。

单体启动

jeecg-system-start
├── 依赖: jeecg-system-local-api(本地调用)
├── 依赖: jeecg-system-biz(业务逻辑)
├── 依赖: jeecg-boot-module-airag(AI 模块)
├── 依赖: jeecg-online(低代码引擎)
└── 启动类: JeecgSystemApplication.java

所有模块在同一个 JVM 进程中运行,方法调用是本地调用。

微服务启动

启动命令: mvn clean package -P SpringCloud
jeecg-cloud-nacos → Nacos 注册/配置中心(端口 8848)
jeecg-cloud-gateway → API 网关(端口 9999)
jeecg-system-cloud-start → System 服务(端口 8080)
jeecg-demo-cloud-start → Demo 服务(独立端口)
jeecg-visual/monitor → 监控服务(端口 9111)

微服务组件

组件端口职责
Nacos8848服务注册与发现、统一配置中心
Gateway9999API 网关、路由转发、限流
Sentinel9000熔断降级限流
System Cloud Start8080系统服务(用户、角色、权限、AI 模块)
XXL-Job9080分布式任务调度
监控9111Spring Boot Admin 监控面板

Gateway 网关配置

网关是微服务的统一入口:

# Gateway 路由配置
spring:
cloud:
gateway:
routes:
- id: jeecg-system
uri: lb://jeecg-system # 通过 Nacos 服务名路由
predicates:
- Path=/jeecg-boot/sys/**
- id: jeecg-demo
uri: lb://jeecg-demo
predicates:
- Path=/jeecg-boot/demo/**

限流配置(基于 Redis 令牌桶):

spring:
cloud:
gateway:
default-filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20

配置切换机制

通过 Maven Profile 切换:

<!-- 根 pom.xml -->
<profiles>
<profile>
<id>SpringCloud</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<modules>
<module>jeecg-server-cloud</module>
</modules>
</profile>
</profiles>
  • 默认构建mvn clean package):只构建单体模块
  • 微服务构建mvn clean package -P SpringCloud):额外构建微服务模块

统一权限在两种模式下的表现

模式认证方式权限传递
单体Shiro Filter 拦截,用户信息存 ThreadLocal直接读取 ThreadLocal
微服务Gateway JWT 验证,用户信息放请求头通过 X-Access-Token 请求头传递

关键设计:权限验证逻辑在 jeecg-boot-base-core 中统一实现,通过判断是否为微服务模式选择不同的验证路径:

// 伪代码:权限验证
if (isMicroService()) {
// 微服务:从请求头获取 Token
token = request.getHeader("X-Access-Token");
} else {
// 单体:从 Session 获取
token = TokenUtils.getTokenByRequest(request);
}

问题与规避

陷阱表现对策
local-api 与 cloud-api 接口不一致切换后编译错误或运行时异常保持两套 API 接口定义完全一致
微服务模式下 Nacos 未启动Gateway 无法路由,服务注册失败启动顺序:Nacos → Gateway → System
单体模式下 Shiro 与 Flyway 冲突懒初始化干扰 Flyway 自动配置application.yml 中显式排除 Flyway 自动配置
Feign 调用超时大文件上传或长流程操作超时配置 feign.client.config.default.connect-timeoutread-timeout
Gateway 限流误伤正常请求被限流拦截配置白名单路径(如静态资源、健康检查)

设计取舍

单体优先 vs 微服务优先

JeecgBoot 选择:单体优先,微服务可选。

方案适用场景
单体优先中小项目、快速原型、团队规模小
微服务优先大型企业级项目、多团队协作

JeecgBoot 定位为低代码平台,目标用户多数是中小团队。单体优先降低了入门门槛,当业务增长需要拆分时,平滑切换为微服务。

API 接口双实现 vs 统一接口适配层

JeecgBoot 选择:接口名一致,通过依赖切换。

方案优势代价
接口名一致(当前方案)业务代码零修改,依赖替换即可需要维护两套接口定义文件
统一接口 + 适配层只需维护一套接口适配层增加复杂度,远程调用性能损耗

接口名一致是最简单的方案——业务代码完全不受影响。代价是需要维护两份接口定义,但接口变更频率远低于业务代码,管理成本可控。


参考来源