后端分层:三层怎么分工
今天建立后端的"分层地图":Controller(薄)→ Service(业务)→ SDK/K8s(存储)。理解了这三层的边界,后面每读一个功能就知道"该去哪一层找"。
三层总览
console/controller/):@RestController,只做"接收 HTTP + 校验入参 + 委派",不含业务逻辑。sdk/service/kubernetes/):KubernetesClientService 直接读写 K8s;KubernetesModelConverter 做"领域模型 ↔ K8s 对象"转换。Controller 层:薄
统一风格:@RestController + @RequestMapping("/v1/...") + @Validated,字段用 @Resource 注入 SDK service,返回 ResponseEntity<Response<T>>。以 RoutesController.java:45-52 为例:
@RestController
@RequestMapping("/v1/routes")
@Validated
public class RoutesController {
@Resource private RouteService routeService; // 昨天 SdkConfig 注册的 Bean
// ...
}
routeService.add(route) 一句话交给下一层。真正的业务在 Service 里。Day 04 会把全部控制器和端点列一遍。Service 层:业务
Service 是"编排中枢"。比如"创建路由"不是简单写一个 Ingress——RouteServiceImpl.add(RouteServiceImpl.java:121-136)会:① 把 Route 转成 Ingress;② 调 K8s 创建;③ 还要 writeAuthConfigResources 写鉴权相关资源。这种"一个操作牵连多个 K8s 资源"的编排,正是 Service 层的价值。
AiRouteServiceImpl 一个方法里编排完成。POST /v1/routes(带鉴权),但 RouteServiceImpl.add 在厨房里做了三道工序:①
route2Ingress 把 Route 翻成 Ingress → ② createIngress 写进 K8s → ③ writeAuthConfigResources 再写一份鉴权资源。一次点击 → 多个 K8s 对象,这种"打包编排"就是 Service 层存在的理由。(完整链路 Day 10 逐行追。)SDK/K8s 存储层
最底层是 sdk/service/kubernetes/KubernetesClientService.java(813 行)——它把每类 K8s 资源的增删改查封成方法:Ingress、ConfigMap、Secret、以及 CRD(McpBridge/WasmPlugin/EnvoyFilter)。旁边的 KubernetesModelConverter.java(2102 行)负责把领域对象翻译成 K8s 对象。
KubernetesClientService 就是它的"DAO",KubernetesModelConverter 就是它的"ORM 映射"。第 2 周整周都在拆这两个类。两类 Service(重要区分)
- console 自身业务 service(
console/service/,是 Spring@Service):SessionService(登录)、DashboardService(仪表盘)、ConfigServiceImpl(系统配置)。 - SDK 资源 service(
sdk/service/,不是 Spring 组件):RouteServiceImpl、ServiceServiceImpl、WasmPluginServiceImpl、AiRouteServiceImpl…由HigressServiceProvider手动装配,再在SdkConfig注册为 Bean。
@Service 注解被 Spring 自动扫描,后者是 SDK 里手写 new 出来的。包结构地图
# console 模块
HigressConsoleApplication.java 启动类
WebMvcInitializer.java 静态资源 + SPA 回退
config/ SdkConfig, SwaggerConfig
controller/ 17+ 控制器 + ai/ + mcp/ + dto/ + util/ + exception/
service/ ConfigService, DashboardService, SessionService, SystemService
aop/ ApiStandardizationAspect(切面), AllowAnonymous
client/grafana/ Grafana 客户端
# sdk 模块
config/ HigressServiceConfig
service/ HigressServiceProvider(Impl), RouteServiceImpl, ...
service/kubernetes/ KubernetesClientService, KubernetesModelConverter, crd/
service/ai/ AiRouteServiceImpl, LlmProviderServiceImpl, 各厂商 Handler
service/consumer/ ConsumerServiceImpl, KeyAuthCredentialHandler
service/mcp/ McpServerService...
model/ Route, Service, Domain, ai/*, consumer/*, mcp/*
无数据库!(本项目最反直觉的一点)
higress-console,见 ConfigServiceImpl.java:42-43)里。为什么?因为 K8s 本身就是个带持久化、带 watch、带一致性的"数据库"——Console 复用它,就不用自己维护数据库、备份、迁移。这也让 Console 天然"无状态",重启不丢数据、可以随便扩副本。👶 小白:没数据库,那我建的路由重启后不就没了吗?
👨🏫 老师:不会。数据根本不在 Console 进程里,而是写进了 K8s 这个"带持久化的档案室"。Console 只是往档案室存/取,自己是无状态的——重启、扩到 3 个副本,都读同一份档案,数据一致也不丢。这正是"用 K8s 当数据库"白捡的好处。
ConfigServiceImpl.java:42-43)——全课不会出现任何数据库。今日小结 + 动手
🧠 今天你应该能回答
- 后端三层分别是什么?各自的边界?
- 两类 Service 怎么区分?谁被 Spring 扫描、谁是手写 new?
- "存储层"在这个项目里指哪两个类?
- 为什么说 Console 没有数据库?它的数据存哪?
✋ 动手
cd /Users/bitmart/work/codes/github/higress-group/higress-console/backend
ls console/src/main/java/com/alibaba/higress/console/controller/
ls sdk/src/main/java/com/alibaba/higress/sdk/service/
ls sdk/src/main/java/com/alibaba/higress/sdk/service/kubernetes/
sed -n '45,52p' console/src/main/java/com/alibaba/higress/console/controller/RoutesController.java
RoutesController 的 CRUD,看校验、状态码策略、统一响应怎么做。