feat: 文档更新

This commit is contained in:
2026-07-14 17:11:58 +08:00
parent 6e06cbf5b5
commit 1f119edb7c
3 changed files with 190 additions and 122 deletions

View File

@@ -1,9 +1,10 @@
# 缓存序列化结构变更检测 — 实施方案
> 版本v0.1
> 日期2026-07-13
> 版本v0.2
> 日期2026-07-14
> 技术栈Java 11 + Maven + JavaParser
> 目标仓库:`redisCheck`(工具) / `jnpf-java-cloud`(被检测业务仓库)
> 目标仓库:`redisCheck`(工具) / `jnpf-java-cloud`(被检测业务仓库)
> 当前阶段:**Phase 1 + Phase 2 已完成**Phase 3 待做
---
@@ -56,7 +57,7 @@
4. 通过企微机器人发送通知
5. 通过开关控制 **仅通知****阻断流水线**
### 1.3 非目标(第一版不做)
### 1.3 非目标
- 不连接真实 Redis 实例做运行时校验
- 不扫描 Maven 依赖 jar 中的类(仅分析业务仓库源码)
@@ -71,20 +72,20 @@
### 2.1 Redis 序列化方式
| 类型 | 出现频率 | 第一版策略 |
|------|----------|------------|
| `JSON.toJSONString(obj)` / `JSONObject.toJSONString(obj)` | 高 | **重点支持** |
| `JsonUtil.getObjectToString(obj)` | 高 | **重点支持**按 Fastjson/Jackson 默认字段规则推断 |
| `RedisTemplate.opsForValue().set(key, obj)` 直接写对象 | 中 | 第二阶段支持 |
| `RedisTemplate.opsForHash().put(key, field, obj)` | 中 | 第二阶段支持 |
| `StringRedisTemplate` 写 JSON 字符串 | 高 | **重点支持** |
| 类型 | 出现频率 | 策略 |
|------|----------|------|
| `JSON.toJSONString(obj)` / `JSONObject.toJSONString(obj)` | 高 | **支持**W01/W02 |
| `JsonUtil.getObjectToString(obj)` | 高 | **支持**W03 |
| `RedisTemplate.opsForValue().set(key, obj)` 直接写对象 | 中 | **已支持**W04 |
| `RedisTemplate.opsForHash().put(key, field, obj)` | 中 | **已支持**W05 |
| `StringRedisTemplate` 写 JSON 字符串 | 高 | **支持** |
| 锁 / 计数器 / token 简单值 | 高 | **默认忽略** |
### 2.2 Key 与实体映射
- 不存在统一的「Key → 类型」注册中心
- 存在大量 `static final String``String.format(...)``buildCacheKey(...)` 等模式
- 第一版采用:**写入点静态推断 + 可选 YAML 人工补充映射**
- 因此采用:**写入点静态推断 + 可选 YAML 人工补充映射**
### 2.3 多模块特征
@@ -98,10 +99,9 @@
### 3.1 交付形态
沿用现有 `code-checker` 模式(见 `redisCheck/.gitea/demo.yaml`
```text
redisCheck 仓库
schemaCheck 仓库
├── 开发 Java 分析工具
├── mvn package 打 fat-jar
├── 发布到 Nexuscom.codechecker:cache-schema-checker:{version}
@@ -144,7 +144,7 @@ flowchart TB
2. **Diff 驱动**:只分析本次 push 变更涉及的文件及其关联类型
3. **本仓限定**:类型解析仅在业务仓库 `src/main/java` 范围内
4. **可配置**:忽略规则、严重级别、通知开关、阻断开关均可 YAML 配置
5. **可演进**第一版聚焦 JSON 字符串写入,后续扩展 Template 直写对象
5. **可演进**已覆盖 JSON 字符串写入 Template 直写 / Hash后续可扩展读路径反向确认、报告落盘等
---
@@ -170,7 +170,7 @@ flowchart TB
## 5. 工程结构redisCheck 仓库)
```text
redisCheck/
schemaCheck/
├── pom.xml # 单模块工程(无父子结构)
├── docs/
│ ├── 实施方案.md
@@ -180,19 +180,19 @@ redisCheck/
│ ├── main/
│ │ ├── resources/
│ │ │ └── default-config.yaml # 内置默认配置(随 jar 发布)
│ │ └── java/com/codechecker/redis/
│ │ └── java/com/codechecker/cache/
│ │ ├── cli/ # 命令行入口
│ │ ├── config/ # 配置模型
│ │ ├── git/ # Git 操作
│ │ ├── analyze/ # 编排与工作树扫描
│ │ ├── detector/ # Redis 写入点检测
│ │ ├── schema/ # Schema 提取
│ │ ├── detector/ # Redis 写入点检测W01~W05
│ │ ├── schema/ # Schema 提取与注解
│ │ ├── diff/ # 结构对比
│ │ ├── key/ # Key 推断
│ │ ├── report/ # 报告
│ │ ├── report/ # 报告 / 企微 Markdown
│ │ └── notify/ # 企微通知
│ └── test/
│ ├── resources/fixtures/tenant/
│ ├── resources/fixtures/{tenant,lock,template}/
│ └── java/...
├── .gitea/
│ ├── workflows/cache-schema-check.yaml
@@ -205,7 +205,7 @@ redisCheck/
```xml
<groupId>com.codechecker</groupId>
<artifactId>cache-schema-checker</artifactId>
<version>1.0.0-SNAPSHOT</version>
<version>1.0.0</version>
```
打包为 **shaded/fat jar**,主类:`com.codechecker.cache.cli.CacheSchemaCheckerMain`
@@ -273,20 +273,20 @@ git diff --name-only {old-sha} {new-sha} -- '*.java'
**变更文件** 中扫描以下 AST 模式:
| 模式 ID | 匹配表达式 | 提取信息 |
|---------|------------|----------|
| W01 | `redisUtil.insert(key, JSON.toJSONString(expr), ttl)` | key 表达式、value 表达式 |
| W02 | `redisTemplate.opsForValue().set(key, JSON.toJSONString(expr), ...)` | 同上 |
| W03 | `stringRedisTemplate.opsForValue().set(key, JsonUtil.getObjectToString(expr), ...)` | 同上 |
| W04 | `redisTemplate.opsForValue().set(key, expr, ...)` 且 expr 非字面量 | 第二阶段 |
| W05 | `redisTemplate.opsForHash().put(key, field, expr)` | 第二阶段 |
| W06 | `JSON.parseObject(cacheValue, Xxx.class)` | 辅助反向确认读取类型 |
| 模式 ID | 匹配表达式 | 提取信息 | 状态 |
|---------|------------|----------|------|
| W01 | `redisUtil.insert(key, JSON.toJSONString(expr), ttl)` | key 表达式、value 表达式 | ✅ |
| W02 | `redisTemplate.opsForValue().set(key, JSON.toJSONString(expr), ...)` | 同上 | ✅ |
| W03 | `stringRedisTemplate.opsForValue().set(key, JsonUtil.getObjectToString(expr), ...)` | 同上 | ✅ |
| W04 | `redisTemplate.opsForValue().set(key, expr, ...)` 且 expr 非字面量 | 直写对象类型 | ✅ Phase 2 |
| W05 | `redisTemplate.opsForHash().put(key, field, expr)` | Hash 写出 value 类型 | ✅ Phase 2 |
| W06 | `JSON.parseObject(cacheValue, Xxx.class)` | 辅助反向确认读取类型 | 未做 |
**忽略规则**(自动):
- value 为字符串字面量、数字、`UUID``"1"`
- 方法名含 `setIfAbsent``increment``delete``remove``expire`
- key 匹配 `ignore_key_patterns` 配置
- value 为字符串字面量、数字、`UUID``"1"`琐碎值
- 方法名含 `setIfAbsent``increment``delete``remove``expire`
- key 匹配 `ignore.key_patterns` 配置(锁 / token / 登录计数等)
#### Step 5类型推断
@@ -308,15 +308,16 @@ redisUtil.insert(buildCacheKey(encode), JSON.toJSONString(envelope), ttl);
4. 递归展开 `TenantVO``dbName: String``linkList: List<TenantLinkModel>`
5. 继续展开 `TenantLinkModel` 全部字段
**注解处理**(第一版)
**注解处理**
| 注解 | 行为 |
|------|------|
| `@JSONField(serialize = false)` | 排除字段 |
| `@JSONField(name = "xxx")` | 字段名映射 |
| `@JsonIgnore` | 排除字段 |
| `@JsonProperty("xxx")` | 字段名映射 |
| `@Schema` | 忽略(不影响序列化) |
| 注解 | 行为 | 状态 |
|------|------|------|
| `@JSONField(serialize = false)` | 排除字段 | ✅ |
| `@JSONField(name = "xxx")` | 字段名映射 | ✅ |
| `@JsonIgnore` | 排除字段 | ✅ |
| `@JsonProperty("xxx")` | 字段名映射 | ✅ |
| `@JsonIgnoreProperties({...})` | 类级忽略字段 | ✅ Phase 2 |
| `@Schema` | 忽略(不影响序列化) | ✅ |
#### Step 6生成 JSON Schema
@@ -367,18 +368,28 @@ redisUtil.insert(buildCacheKey(encode), JSON.toJSONString(envelope), ttl);
生成 `CheckReport`,包含:
- 仓库名、分支、old/new sha、提交人、时间
- 变更列表(按严重级别排序)
- 每项Key 模式、写入位置(类#方法:行号)、旧结构、新结构、变更摘要
- 按 Key 聚合的结构变更(骨架 before/after+ 字段级明细
- 每项通用展示:**Key**、**位置**`Class#method:line`)、**类型**、旧/新序列化骨架
调用企微 Webhook 发送 Markdown 消息。
企微 Markdown 规则:
- 抬头不含 mode / P0~P2 汇总;正文按 Key 展示骨架
- **删除字段**:旧骨架中橙色 `<font color="warning">`
- **新增字段**:新骨架中绿色 `<font color="info">`
- key 未解析时展示源码表达式 + 灰色「key 未解析)」
- 单条超 4096 UTF-8 字节时按 Key 拆成多条依次发送
CI 控制台额外输出字段明细(含严重级别),再打印与企微一致的 Markdown。
调用企微 Webhook 发送 Markdown支持 `--dry-run` 仅本地输出)。
#### Step 9退出码
| 条件 | 退出码 |
|------|--------|
| 无变更 / 仅 P2 | 0 |
| `mode=notify` 且存在 P0/P1 | 0仍通知 |
| `mode=block` 且存在 P0/P1/P2 | 1 |
| `enabled=false` / 无变更 | 0 |
| `mode=notify` 且存在变更 | 0仍通知 |
| `mode=block` 且存在任意结构变更 | 1 |
| 配置错误 / 执行异常 | 2 |
---
@@ -442,9 +453,11 @@ mode: notify
# 是否发送企微通知
notify:
enabled: true
webhook_env: WECOM_ROBOT_WEBHOOK
webhook_url: "" # 企微 Webhook 完整 URL兼容旧字段 webhook_env
```
企微消息约定见 `docs/配置说明.md` §5**位置/类型**为每个 Key 的通用项;删除字段橙色、新增字段绿色。
---
## 9. CI 集成方案
@@ -492,43 +505,44 @@ jobs:
## 10. 分阶段交付计划
### Phase 1 — MVP约 1.5 周)
### Phase 1 — MVP约 1.5 周)
**目标**:跑通端到端链路,覆盖租户缓存典型场景。
| 任务 | 产出 |
|------|------|
| Maven 工程骨架 + CLI | 可执行 fat-jar |
| Git diff 扫描 | 变更文件列表 |
| W01~W03 写入点检测 | 覆盖 JSON 字符串写入 |
| 基础 Schema 提取 | 支持普通类、内部类、List、嵌套 |
| Schema Diff P0/P1 | 字段增删、包装、路径迁移 |
| 企微通知 | Markdown 消息 |
| notify/block 开关 | 配置驱动 |
| 夹具测试 | TenantVO/CacheEnvelope 样本 |
| 任务 | 产出 | 状态 |
|------|------|------|
| Maven 工程骨架 + CLI | 可执行 fat-jar | ✅ |
| Git diff 扫描 | 变更文件列表 | ✅ |
| W01~W03 写入点检测 | 覆盖 JSON 字符串写入 | ✅ |
| 基础 Schema 提取 | 支持普通类、内部类、List、嵌套 | ✅ |
| Schema Diff P0/P1 | 字段增删、包装、路径迁移 | ✅ |
| 企微通知 | 按 Key 骨架 Markdown | ✅ |
| notify/block / enabled | 配置驱动 | ✅ |
| 夹具测试 | TenantVO/CacheEnvelope 样本 | ✅ |
**验收标准**
-`TenantDbContentCacheHelper` 的结构变更能输出 P0 报告
-`TenantDbContentCacheHelper` 的结构变更能输出报告并通知
- 流水线 push 后能收到企微通知
- `mode=block` 时任意 P0/P1/P2 变更导致 exit 1
- `mode=block` 时任意结构变更导致 exit 1
### Phase 2 — 增强(约 1 周)✅
| 任务 | 说明 | 状态 |
|------|------|------|
| W04/W05 模式 | RedisTemplate 直写对象、Hash 写入 | 已完成 |
| 注解完整支持 | Fastjson/Jackson 注解(含 `@JsonIgnoreProperties` | 已完成 |
| Key 推断增强 | `String.format`、常量拼接追溯`buildXxxKey` | 已完成 |
| 忽略规则完善 | 锁/计数器/token/字面量/setIfAbsent 自动过滤 | 已完成 |
| 多模块性能优化 | 并行读文件、索引批量装载、manual_mappings 覆盖 | 已完成 |
| W04/W05 模式 | RedisTemplate 直写对象、Hash 写入 | |
| 注解完整支持 | Fastjson/Jackson`@JsonIgnoreProperties` | |
| Key 推断增强 | `String.format`、常量拼接、`buildXxxKey` | |
| 忽略规则完善 | 锁/计数器/token/字面量/setIfAbsent | ✅ |
| 多模块性能 | 并行读文件、索引批量装载、`manual_mappings` | ✅ |
| 企微高亮 | 删除橙 `warning` / 新增绿 `info`;位置+类型通用项 | ✅ |
### Phase 3 — 运营(约 0.5 周)
| 任务 | 说明 |
|------|------|
| 报告落盘 | 可选输出 JSON 报告文件 |
| 误报反馈 | `suppressions` 配置支持按写入点忽略 |
| 误报反馈 | `suppressions` 按写入点 / change_types 精细忽略 |
| 更多业务场景覆盖 | 考勤、文件下载进度等 |
---
@@ -548,10 +562,9 @@ jobs:
| 夹具 | 验证点 |
|------|--------|
| `tenant-cache/` | 包装结构变更 P0 |
| `attendance-base-setting/` | Map 结构缓存 |
| `evaluate-config/` | VO 字段新增 P1 |
| `lock-only/` | 应被忽略 |
| `fixtures/tenant/` | 包装结构变更TenantVO → CacheEnvelope |
| `fixtures/lock/` | 锁/计数器/token 应被忽略 |
| `fixtures/template/` | W04 Template 直写 |
### 11.3 端到端测试
@@ -577,13 +590,13 @@ jobs:
| # | 决策项 | 结论 |
|---|--------|------|
| 1 | 阻断范围 | `block` 模式下 **P0/P1/P2 全部阻断**exit 1 |
| 1 | 阻断范围 | `block` 模式下 **任意结构变更均阻断**exit 1 |
| 2 | 发布坐标 | 独立产物 `com.codechecker:cache-schema-checker:1.0.0` |
| 3 | 配置归属 | **双层配置**jar 内 `default-config.yaml` + 业务仓覆盖合并 |
| 4 | 上线策略 | 先 `notify` 观察 **1 周**,稳定后手动切 `block` |
| 5 | 检测范围 | **仅 `src/main/java`**,不扫描测试代码 |
以上决策已纳入实施方案,可进入开发阶段
以上决策已纳入实施方案**Phase 1 / Phase 2 已交付**,可进入 Phase 3 或业务仓全量观察
---