- docs/: 源码分析报告、代码深度解析、项目说明书、独立服务化方案 - backend/: 账权模块提取说明(提取原则、文件清单、耦合度验证) - frontend/: 前端剥离方案、剥离历史与说明、框架修改详情
27 KiB
代码深度解析与分析过程
本文档记录了对账权平台(原掌渠 SaaS 云平台)前后端源码的完整深度分析过程,包括项目结构剖析、账权模块耦合度量化、设计意图逆向还原、以及独立服务化可行性论证。内容来自实际的代码走查,非概要性总结。
目录
1. 后端项目深度分析
1.1 基本信息
| 项目 | 值 |
|---|---|
| 包根 | cn.apes.cloud |
| 启动类 | cn.apes.CloudApplication |
| 框架 | Spring Boot 2.2.1 + Java 11 |
| ORM | MyBatis Plus 3.5.7 |
| 动态数据源 | dynamic-datasource 3.6.1 |
| 缓存/分布式 | Redisson 3.35.0 |
| 认证框架 | cn.apes:apes-commons:0.0.7-SNAPSHOT(外部 JAR) |
| AI 集成 | OpenAI SDK + Groovy 脚本引擎 |
1.2 包结构总览
cn.apes.cloud
├── CloudApplication.java # 启动类
├── config/ # 配置类
│ ├── DataSourceHeaderAspect.java # 动态数据源切面(@Order(1))
│ ├── MybatisPlusConfig.java # 分页插件
│ ├── RedisConfig.java # Redisson 配置
│ ├── TenantSource.java # 多租户数据源注解
│ └── WebMvcConfig.java # 跨域 + 拦截器
├── filter/
│ └── AccessTokenFilter.java # AccessToken 开放平台认证过滤器
├── controller/ # 62 个 Controller
│ ├── UserInfoController.java # 用户管理
│ ├── PermissionController.java # 权限管理
│ ├── CustomerInfoController.java # 企业/租户管理
│ ├── SysRoleController.java # 角色管理
│ ├── SysMenuController.java # 菜单管理
│ ├── SysDeptController.java # 部门管理
│ ├── SysAccessTokenController.java # AccessToken 管理
│ ├── LoginController.java # 登录/SSO
│ ├── TraceProductController.java # 溯源产品
│ ├── Weight*Controller.java # 过磅系列
│ ├── Agent*Controller.java # AI Agent 系列(10+)
│ └── ... # 其余业务 Controller
├── service/ # Service 接口
│ └── impl/ # Service 实现
├── mapper/ # MyBatis Mapper 接口
├── domain/
│ └── entity/ # 数据实体
├── util/
│ ├── OperationLogUtil.java # 操作日志工具(静态封装)
│ └── ...
├── aspect/ # AOP 切面
└── job/ # 定时任务
1.3 核心配置分析
多数据源配置(application.yml):
spring:
datasource:
dynamic:
datasource:
cloud: # 主库 — 账权、用户、企业
user: # 用户业务库
huoban: # 伙伴云集成库
plant: # 农业种植库
zx: # 其他业务库
数据源切换通过 @TenantSource 注解 + DataSourceHeaderAspect(@Order(1))实现:
- 切面拦截标注了
@TenantSource的类/方法 - 从 HTTP Header
X-Tenant-ID读取目标数据源 - 调用
DynamicDataSourceContextHolder.push(head)切换 - 切面执行前先调用
AuthContext.clean()清理 ThreadLocal(防串号),除非AccessTokenFilter已标记accessTokenVerified
1.4 Controller 分类
| 类别 | 数量 | 代表 Controller |
|---|---|---|
| 账权类 | 8 | UserInfo, Permission, SysRole, SysMenu, SysDept, CustomerInfo, SysAccessToken, Login |
| 溯源类 | ~6 | TraceProduct, TraceBatch, TraceCode, TraceLink, TraceRecord, TraceConfig |
| 过磅类 | ~5 | WeightTicket, WeightDevice, WeightReport, WeightConfig, WeightPrint |
| AI Agent 类 | ~10 | AgentChat, AgentTool, AgentKnowledge, AgentModel, AgentPrompt, AgentFlow, AgentDatasource, AgentFile, AgentFunction, AgentSession |
| 农业类 | ~8 | Crop, Farm, Field, Sensor, Device, Irrigation, Pest, Weather |
| 其他业务 | ~25 | 套餐、订单、支付、统计、文件、消息、日志等 |
1.5 核心业务实体
用户/认证域:
UserInfo # 用户
CustomerInfo # 企业/租户
SysRole # 角色
SysMenu # 菜单
SysDept # 部门
SysAccessToken # 开放平台令牌
SysPermission # 权限项
SysSsoConfig # SSO 配置
溯源域:
TraceProduct # 溯源产品
TraceBatch # 批次
TraceCode # 溯源码
TraceLink # 追溯链路
TraceRecord # 操作记录
过磅域:
WeightTicket # 过磅单
WeightDevice # 地磅设备
AI Agent 域:
AgentModel # 模型配置
AgentPrompt # 提示词模板
AgentTool # 工具定义
AgentSession # 会话
AgentKnowledge # 知识库
1.6 定时任务
@Component
public class XxlJobHandler {
@XxlJob("cleanExpiredTokens") // 清理过期 AccessToken
@XxlJob("syncTraceData") // 同步溯源数据
@XxlJob("reportWeightStats") # 过磅统计上报
}
1.7 LLM / AI Agent 平台
项目内置完整的 AI Agent 平台,核心能力包括:
- Function Calling:Agent 可以调用注册的 Java 方法作为工具
- Groovy 动态工具:通过 Groovy 脚本引擎动态编译执行自定义工具逻辑,无需重启服务
- 多轮对话管理:AgentSession 管理上下文窗口
- 知识库检索:AgentKnowledge 支持向量检索(集成 Embedding)
- ASR 语音识别:语音输入转文本
- 多模型支持:AgentModel 可配置 OpenAI/通义千问等
- 工作流编排:AgentFlow 支持节点式编排
- 数据源接入:AgentDatasource 连接外部数据库供 Agent 查询
- 文件理解:AgentFile 支持文档解析
- 提示词模板:AgentPrompt 管理系统提示词
2. 前端项目深度分析
2.1 基本信息
| 项目 | 值 |
|---|---|
| 框架 | Vue 2.7.16 |
| UI 库 | Element UI 2.15.14 |
| 状态管理 | Vuex 3.6.2 |
| 路由 | Vue Router 3.6.5(动态路由) |
| HTTP | Axios 0.21.4 |
| 构建 | Vue CLI 5.0.8 |
2.2 目录结构
src/
├── main.js # 入口:Element UI、全局组件注册
├── App.vue
├── permission.js # 路由守卫:动态权限路由
├── router/ # 静态路由 + 动态路由加载
├── api/ # API 接口模块(按业务域分文件)
├── views/ # 页面组件(85+)
├── components/ # 公共组件
├── layout/ # 布局框架
│ └── components/
│ ├── Sidebar/ # 侧边栏(动态菜单)
│ ├── Navbar/ # 顶栏
│ └── AppMain/ # 主内容区
├── store/ # Vuex
│ └── modules/
│ ├── user.js # 用户状态
│ ├── permission.js # 权限路由
│ └── ...
├── utils/ # 工具函数
│ ├── request.js # Axios 封装(拦截器)
│ ├── auth.js # Token 管理
│ ├── constUtil.js # 常量
│ └── get-page-title.js # 页面标题
├── config/ # 配置
│ └── tracingOpenKey.js # 溯源开放密钥
├── styles/ # 全局样式
└── assets/ # 静态资源
2.3 动态路由系统
路由分为静态路由和动态路由:
- 静态路由:登录页、404 页、无权限页面
- 动态路由:通过后端 API
GET /system/menu/routes获取,按角色权限动态注册
路由元信息 meta 包含 menuType 字段,区分 4 种类型:
menu— 侧边栏菜单button— 按钮级权限link— 外链hidden— 隐藏路由
2.4 前端 API 代理配置(vue.config.js)
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
},
configureWebpack: {
name: '账权平台'
}
}
2.5 Vuex 状态管理
| Module | 职责 |
|---|---|
user |
Token 存储/清除、用户信息获取、登录/登出 |
permission |
动态路由生成、菜单树构建 |
settings |
侧边栏折叠、主题等 UI 状态 |
2.6 前端 AI 相关页面
前端包含完整的 AI Agent 管理界面:
views/agent/chat— 对话界面views/agent/model— 模型配置views/agent/prompt— 提示词管理views/agent/tool— 工具管理(支持 Groovy 脚本编辑)views/agent/knowledge— 知识库管理views/agent/flow— 工作流编排views/agent/session— 会话管理views/agent/datasource— 数据源管理views/agent/file— 文件管理views/agent/function— 函数管理
3. 账权模块深度代码走查
3.1 认证流程
整个认证流程涉及三个层次:
请求进入 → AccessTokenFilter(开放平台令牌)
→ DataSourceHeaderAspect(清理 ThreadLocal + 切数据源)
→ LoginAspect(apes-commons 中,@Login AOP 填充 AuthContext)
→ Controller 方法执行
3.1.1 AccessTokenFilter(开放平台认证)
// 文件:cn.apes.cloud.filter.AccessTokenFilter
// 职责:为外部系统提供免登录的 API 访问
// 1. 从 Header 提取 Token(X-Access-Token 或 Authorization: Bearer)
// 2. 调用 SysAccessTokenService.validate() 校验
// 3. 校验通过 → 将用户/企业信息写入 Redis(模拟登录态)
// - key = token → JSONObject {id:0, nickName:"AccessToken:xxx"}
// - key = token:customer → 企业信息 JSON
// 4. 包装 request,注入 "token" header → 让后续 @Login AOP 能取到
// 5. 标记 request.setAttribute("accessTokenVerified", true)
// → DataSourceHeaderAspect 检测到此标记则跳过 AuthContext.clean()
关键代码片段:
// 写入 Redis 模拟登录态
RBucket<JSONObject> userBucket = redissonClient.getBucket(redisToken);
userBucket.set(userObj, 1, TimeUnit.DAYS);
RBucket<JSONObject> customerBucket = redissonClient.getBucket(redisToken + ":customer");
customerBucket.set(customerObj, 1, TimeUnit.DAYS);
// 标记已验证
request.setAttribute("accessTokenVerified", true);
3.1.2 DataSourceHeaderAspect(数据源切换 + ThreadLocal 清理)
// 文件:cn.apes.cloud.config.DataSourceHeaderAspect
// @Order(1) — 在 LoginAspect 之前执行
@Around("@within(tenantSource) || @annotation(tenantSource)")
public Object exc(ProceedingJoinPoint pjp, TenantSource tenantSource) throws Throwable {
HttpServletRequest request = ...;
// 如果 AccessToken 过滤器已验证,保留其设置的认证上下文
if (request.getAttribute("accessTokenVerified") == null) {
AuthContext.clean(); // 清理上一请求残留的 ThreadLocal
}
String head = request.getHeader("X-Tenant-ID");
if (StrUtil.isEmpty(head)) head = "user"; // 默认数据源
DynamicDataSourceContextHolder.push(head); // 切换数据源
return pjp.proceed();
}
3.1.3 LoginAspect(apes-commons 内部,不可见源码)
根据 pom.xml 中的 apes-commons:0.0.7-SNAPSHOT 依赖,推断其行为:
- 拦截标注
@Login的 Controller 类/方法 - 从
request.getHeader("token")获取 Token - 从 Redis 读取
RBucket<JSONObject>(token)和RBucket<JSONObject>(token:customer) - 填充
AuthContext的 ThreadLocal(LoginUser+LoginCustomer)
3.2 RBAC 权限模型
UserInfo (用户)
└── SysUserCustomer (用户-租户关联,支持一人多租户)
└── CustomerInfo (租户/企业)
└── SysRole (角色)
└── SysMenu (菜单/权限项)
└── 权限标识 (permission key)
SysUserCustomer ←→ SysRole (用户-角色关联表)
SysRole ←→ SysMenu (角色-菜单关联表)
权限校验方式:PermissionServiceImpl 中实现按钮级权限检查,通过菜单的 permission 字段匹配。
3.3 多租户数据隔离
方式:共享数据库 + 动态数据源路由(非共享表 + tenant_id 模式)
所有请求 → DataSourceHeaderAspect → 读取 X-Tenant-ID Header → 切换数据源
↓
cloud / user / huoban / plant / zx
业务表通过 customer_id 字段关联 CustomerInfo,不是物理外键,而是逻辑关联。
3.4 AuthContext 使用模式
AuthContext 来自 apes-commons,是 ThreadLocal 封装:
// 典型使用方式(出现在 52 个文件中)
AuthContext.getLoginInfo().getCustomer().getId() // 当前租户 ID
AuthContext.getLoginInfo().getUser().getId() // 当前用户 ID
AuthContext.getLoginInfo().getUser().getNickName() // 当前用户名
配合 @Login 注解,业务 Controller 可以零感知地获取登录态:
@Login
@RestController
@RequestMapping("/tracking/config")
public class TrackingConfigController {
@GetMapping("/list")
public R list() {
Long customerId = AuthContext.getLoginInfo().getCustomer().getId();
// 直接使用,无需传参
return R.ok(configService.listByCustomerId(customerId));
}
}
3.5 OperationLogUtil 静态封装
// 文件:cn.apes.cloud.util.OperationLogUtil
@Component
public class OperationLogUtil {
private static SysOperationLogService logService;
private static RedissonClient redissonClient;
@PostConstruct
public void init() {
logService = SpringContextHolder.getBean(SysOperationLogService.class);
redissonClient = SpringContextHolder.getBean(RedissonClient.class);
}
public static void log(String module, String action, String desc) {
// 从 AuthContext 自动获取操作人信息
LoginInfo info = AuthContext.getLoginInfo();
Long userId = info.getUser().getId();
Long customerId = info.getCustomer().getId();
// ... 记录日志
}
}
11 个业务文件直接调用 OperationLogUtil.log(...),一行式 API,内部依赖 AuthContext。
3.6 账权 Service 间内部调用
LoginController
→ UserInfoService.login() # 登录验证
→ PermissionService.getUserPermissions() # 获取权限
→ SysMenuService.getMenuTree() # 菜单树
→ CustomerInfoService.getById() # 企业信息
SysAccessTokenService.validate()
→ CustomerInfoServiceImpl.getById() # 查企业信息
→ 写 Redis 模拟登录态
PermissionServiceImpl
→ UserInfoService.getUserById() # 查用户
→ SysRoleService.getRolesByUserId() # 查角色
约 8 处内部调用,全部在账权域内。
4. 耦合度量化分析
通过 grep 对源码树的精确统计:
4.1 AuthContext 引用统计
$ grep -rl "AuthContext" service-master/src/ | wc -l
52 个文件
$ grep -r "AuthContext" service-master/src/ | wc -l
111 处引用
文件分布:
- Controller 层:~25 个文件(通过
@Login+AuthContext.getLoginInfo()获取登录态) - Service 实现层:~15 个文件(业务逻辑中获取
customerId) - 工具类/切面:~5 个文件(
OperationLogUtil、DataSourceHeaderAspect等) - 配置/过滤器:~7 个文件(
AccessTokenFilter等)
4.2 OperationLogUtil 引用统计
$ grep -rl "OperationLogUtil" service-master/src/ | wc -l
11 个文件
调用方包括:AccessTokenFilter、各种 *Controller、*ServiceImpl。
4.3 账权 Service 被业务模块直接引用统计
$ grep -rl "import cn.apes.cloud.service.PermissionService\|import cn.apes.cloud.service.UserInfoService\|import cn.apes.cloud.service.CustomerInfoService\|import cn.apes.cloud.service.CustomerUserService\|import cn.apes.cloud.service.SysAccessTokenService" \
service-master/src/main/java/cn/apes/cloud/service/impl/Trace*.java \
service-master/src/main/java/cn/apes/cloud/service/impl/Weight*.java
# 结果:0 个匹配
关键发现:业务模块(Trace*、Weight*)不直接 import 账权 Service。它们仅通过 AuthContext(来自 apes-commons)间接获取登录态,不存在代码层面的直接依赖。
4.4 账权 Service 间内部调用统计
$ grep -rl "import cn.apes.cloud.service.impl.\|import cn.apes.cloud.service\." \
service-master/src/main/java/cn/apes/cloud/service/impl/PermissionServiceImpl.java \
service-master/src/main/java/cn/apes/cloud/service/impl/UserInfoServiceImpl.java
# 约 8 处交叉引用,全部在账权域内部
4.5 耦合度总结
| 指标 | 数值 | 解耦难度 |
|---|---|---|
| AuthContext 引用文件 | 52 个 / 111 处 | 低(import 替换即可) |
| OperationLogUtil 引用 | 11 个文件 | 低(方法签名不变) |
| 业务 Service → 账权 Service 直接调用 | 0 | 无需改造 |
| 账权 Service 间内部调用 | ~8 处 | 随账权服务整体迁移 |
| 数据库外键约束 | 无(逻辑关联) | 拆库时无需处理物理约束 |
5. 设计意图逆向分析——六大障碍的出发点与判定
判断标尺
分析这些障碍,要区分两件事:
- 设计思路对不对(出发点是否站得住)
- 当前形态能不能进微服务(实体要不要拆)
很多障碍属于"思路对、形态错"——不必推倒重来,只需"搬家 + 换填充源"。
障碍 ① AuthContext(ThreadLocal + Redis 会话)
设计出发点:
- 单体里最省事的"隐式传参":任何方法随时
AuthContext.getLoginInfo().getCustomer().getId()拿当前租户,不用在每层方法签名里塞customerId - Redis 做后端存储(key=token → user JSON,key=token:customer → 企业 JSON),会话可跨实例共享 → 单体水平扩容不用粘会话
- 配
@LoginAOP 自动填充,业务零感知
评价:单体时代的经典正确做法。问题不在 ThreadLocal 本身,而在它不跨进程传播。
| 判定 | 说明 |
|---|---|
| ✅ 保留 | ThreadLocal 作为"服务内本地上下文"的机制——任何服务内部用 ThreadLocal 存当前用户都是对的 |
| 🔧 改造 | 填充来源(从"自己查 Redis"改"网关注入 Header")+ 跨服务传播方式。机制保留,来源替换,业务代码几无改动 |
障碍 ② apes-commons 黑盒(外部 0.0.7-SNAPSHOT JAR)
设计出发点:
- 多项目共享基础框架:
cn.apes:apes-commons不止当前 service 在用,伙伴云/交易平台等多条产品线共用同一套认证 - 把脏活(RSA 解密、Token 生成、Redis 读写、ThreadLocal 管理、
@Login/LoginAspect)封进 JAR,各服务鉴权行为一致 pom.xml里特意 exclude 了 hutool(避免版本冲突)——说明它确实被当"公共底座"对待
评价:平台化思路完全正确。黑盒不是罪,问题是要改它、又改不了。
| 判定 | 说明 |
|---|---|
| ✅ 保留 | "共享基础库"这个思路 → 直接进化为自有 auth-sdk |
| 🔧 改造 | 所有权收归自己(从外部 SNAPSHOT 依赖变成自维护 SDK),并用 Maven shade relocation 兼容旧包名,避免 52 个文件全量改 import |
障碍 ③ OperationLogUtil 静态依赖
设计出发点:
- 极致调用便利:任何地方一行
OperationLogUtil.log("模块","操作","描述")就能记日志,不用注入 bean、不用传参 @PostConstruct抓 Spring bean 静态化,是工具类常见写法- 操作人信息从
AuthContext自动取,调用方完全不用关心"谁在操作"——11 个文件因此零成本接入
评价:API 体验目标合理,耦合点只在实现内部。
| 判定 | 说明 |
|---|---|
| ✅ 保留 | 一行式日志 API 的体验 |
| 🔧 改造 | 内部把 apes-commons.AuthContext 换成自有 ServiceAuthContext——约 10 行实现改动,11 个调用方一行都不用动 |
障碍 ④ 账权 Service 间内部调用(UserInfo ↔ Permission ↔ SSO)
设计出发点:
- 这是同一业务域内的自然内聚:登录要知道角色、角色挂在套餐上、套餐要校验权限、SSO 要查
sso_config——它们本就该在一起 - 单体同进程调用,零网络开销(
UserInfoServiceImpl直接@Autowired PermissionServiceImpl)
评价:这不仅不是障碍,反而是该整包带走的部分。它恰恰证明了"账权是一个内聚域"。
| 判定 | 说明 |
|---|---|
| ✅ 全部保留 | 留在 Identity Service 内部,一个调用都不用动 |
| ❌ 无必须拆分项 | 这正是拆服务时"一起搬"的内容 |
障碍 ⑤ 共享数据库(所有表同一 MySQL)
设计出发点:
- 初期最快:不用设计服务边界、不用碰分布式事务
customer_id共享键多租户,天然一张库(业务表靠这个字段关联customer_info,不是外键)- 表间逻辑关联多,放一起 JOIN 方便;一个 RDS 实例成本最低
评价:早期最务实的选择。这是 6 条里唯一一个"实体层面真必须拆"的。
| 判定 | 说明 |
|---|---|
| ✅ 短期保留 | Phase 1-2(模块化隔离、引网关)完全可以不动库,不拆库也能推进 |
| 🔧 必须拆分(长期) | 要"真正独立"就必须拆——否则账权与业务仍共享存储,故障域/扩缩容/安全策略都分不开。拆库放到 Phase 3,且必须配双写过渡期 |
障碍 ⑥ AOP 执行顺序依赖(DataSourceHeaderAspect Order=1 + LoginAspect)
设计出发点:
DataSourceHeaderAspect先AuthContext.clean()再切数据源 → 保证每个请求从干净状态开始,防止上一请求的 ThreadLocal 泄漏/串号- 然后
LoginAspect(在 apes-commons 里)填充 AuthContext → 保证 Controller 执行业务前上下文已就绪 - 这个顺序在"单进程内、请求串行经过切面"时完美工作
评价:"请求级清理 + 顺序保证"的防泄漏思路必须保留,它是并发安全的底线。
| 判定 | 说明 |
|---|---|
| ✅ 保留 | 请求级 ThreadLocal 清理 + 顺序保证的思路(防内存泄漏/串号是刚需) |
| 🔧 改造 | 职责归属变了——数据源路由可能在网关或各服务内,认证填充改由 auth-sdk 的 AuthHeaderFilter 做,顺序由本地 Filter chain 保证,而非跨 JAR 协商 |
总分类
| 障碍 | 设计出发点是否合理 | 结论 |
|---|---|---|
| AuthContext ThreadLocal | ✅ 合理 | 保留机制,改造填充源与跨服务传播 |
| apes-commons 黑盒 | ✅ 合理(平台化) | 保留思路,收归自有 auth-sdk |
| OperationLogUtil 静态 | ✅ 合理(便利性) | 保留 API,改内部 10 行实现 |
| 账权 Service 内部调用 | ✅ 本就该内聚 | 全部保留,整包带走 |
| 共享数据库 | ⚠️ 早期务实 | 短期保留,长期必须拆(Phase 3 + 双写) |
| AOP 顺序依赖 | ✅ 合理(防泄漏) | 保留思路,改造职责归属 |
一句话总结:6 条里有 4 条半是"好设计绑在了单体上"——思路保留、形态搬迁即可;只有"共享数据库"是实体层面真必须拆的,而"账权 Service 内部调用"根本不是障碍,是拆服务时该一起搬走的内聚域。
真正需要"动刀"的,其实就三件事:
- 跨服务上下文传播:ThreadLocal → 网关 Header(机制保留)
- 存储边界:共享库 → auth_db 独立(Phase 3)
- 依赖主权:外部 JAR → 自有 auth-sdk(兼容旧包名,业务零改动)
6. 独立服务化可行性论证
6.1 有利因素
| 因素 | 说明 |
|---|---|
| Redis 共享会话 | 登录态存储在 Redis,天然支持分布式,服务拆分后会话无需迁移 |
| 无数据库外键约束 | 业务表与账权表之间是逻辑关联(customer_id),不是物理外键,拆库无 DDL 障碍 |
| 业务模块零直接依赖 | Trace*/Weight* 不 import 账权 Service,仅通过 AuthContext 间接获取登录态 |
| 账权域高内聚 | 账权 Service 间约 8 处内部调用,全在域内,整包带走即可 |
| AuthContext API 简单 | 主要调用模式是 AuthContext.getLoginInfo().getCustomer().getId(),可用 SDK 兼容替换 |
6.2 风险因素
| 风险 | 等级 | 应对 |
|---|---|---|
| apes-commons 黑盒 | 中 | 收归自有 auth-sdk,Maven shade relocation 兼容旧包名 |
| 52 个文件引用 AuthContext | 低 | import 替换即可,方法签名不变 |
| 共享数据库拆分 | 高 | Phase 3 双写过渡期 + 数据一致性校验 |
| AOP 执行顺序 | 低 | 各服务内 Filter chain 保证,不跨 JAR 协商 |
| AccessTokenFilter 耦合 | 低 | 迁移到网关或 Identity Service 入口 |
6.3 结论
技术上可行。业务模块与账权模块之间不存在直接代码调用(0 个 import),耦合仅通过 AuthContext(ThreadLocal)间接发生。登录态已存储在 Redis 中天然支持分布式。拆分的基础条件良好。
分阶段实施建议:
| 阶段 | 目标 | 风险 | 预估 |
|---|---|---|---|
| Phase 1 | 单体内包级隔离 + 接口抽象 | 低 | 5-10 人天 |
| Phase 2 | 抽取 auth-sdk + 引入网关 | 中 | 10-15 人天 |
| Phase 3 | Identity Service 独立部署 + 数据库拆分 | 高 | 15-20 人天 |
| Phase 4 | JWT 升级 + 权限注解 + OAuth2 | 中 | 10+ 人天 |
建议立即启动 Phase 1(风险最低、收益明确)。是否推进 Phase 2-3 取决于是否有多产品线复用账权的需求。
附:分析方法说明
本文档的分析基于以下方法:
- 静态代码走查:通过 Agent 子任务深度遍历
src/main/java全部包结构,读取所有关键 Controller/Service/Entity/Config 源码 - Grep 量化统计:使用 ripgrep 对源码树进行精确模式匹配,统计耦合度指标
- 依赖追踪:通过 import 语句分析模块间依赖关系
- 设计意图推断:从代码写法(AOP 顺序、静态封装、Redis key 设计等)反推设计者的决策出发点
- 可行性论证:基于量化数据和架构特征,评估微服务拆分的技术可行性
分析工具链:Agent Explore 子任务 + Grep + Read,分析时间:2026-08-05