Files
schemaCheck/docs/配置说明.md
dongzi bef70dd032
All checks were successful
序列化结构检查 / serialization-schema-check (push) Successful in 3s
feat: 文档更新
2026-07-15 18:06:31 +08:00

381 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 序列化结构检测 — 配置说明
> **双层配置**:工具 jar 内置 `default-config.yaml`(默认) + 业务仓库 `.gitea/config/serialization-schema-check-config.yaml`(覆盖)
> 工具坐标:`com.codechecker:serialization-schema-checker:1.0.0`
> 主类:`com.codechecker.cache.cli.SerializationSchemaCheckerMain`
---
## 1. 配置合并机制
```text
jar 内 default-config.yaml工具仓维护
↓ 深度合并
业务仓 serialization-schema-check-config.yaml业务仓维护
最终生效配置
```
- 业务配置**仅需写差异项**,不必复制全部默认规则
- 升级 jar 时,默认忽略规则/检测模式自动跟随工具版本演进
- 业务仓必须存在 `--config` 指定的配置文件(可为仅含 `mode` 的最小文件)
### 1.1 业务仓最小配置示例
```yaml
# jnpf-java-cloud/.gitea/config/serialization-schema-check-config.yaml
enabled: true
mode: notify
notify:
enabled: true
# 推荐直接写完整 Webhook也可用环境变量在流水线注入
webhook_url: ""
include_modules:
- jnpf-tenant
```
流水线通常把 Secret 注入环境或配置文件中的 `webhook_url`。兼容旧字段:`webhook_env`(值为 `http` 开头时当作 URL 使用)。
### 1.2 工具内置默认配置jar 内 default-config.yaml
`redisCheck` 仓库维护,随 jar 发布,默认包含:
- `detection.patterns`**W01~W05**JSON 字符串写入 + Template 直写 + Hash
- `detection.mq_patterns`**MQ01~MQ05、MQ-K01~MQ-K04**RocketMQ / Kafka 生产侧)
- `detection.read_hints_enabled`W06 读侧反序列化类型辅助(默认 true
- `detection.mq_read_hints_enabled`MQ-R 读侧 Listener / parse 补强(默认 true
- `ignore.key_patterns`(锁 / 计数器 / token
- `ignore.mq_destinations`MQ destination 忽略,默认真空)
- `detection.min_confidence``max_field_depth`
- `mode: notify``enabled: true`
---
## 2. 业务仓完整配置示例
```yaml
# 总开关false 时不执行检测、不发通知、流水线直接通过
enabled: true
# 运行模式
# notify - 仅通知,不阻断流水线
# block - 检测到结构变更即阻断流水线exit 1
mode: notify
# 是否扫描测试代码(已确认:不扫描)
scan_test_sources: false
# 源码扫描根目录(仅 main不含 test
source_roots:
- "src/main/java"
# 通知配置
notify:
enabled: true
# Webhook 完整 URL优先
webhook_url: ""
# 兼容旧字段:值为 http 开头时视为 URL
# webhook_env: WECOM_ROBOT_WEBHOOK
# 无变更时是否也发通知(一般 false
notify_on_clean: false
# 消息标题前缀
title_prefix: "[序列化结构变更]"
# 忽略规则
ignore:
# 忽略的 key 模式glob
key_patterns:
- "*:lock"
- "*:lock:*"
- "*lock*"
- "loginCount:*"
- "Authorization:*"
# 忽略的文件路径模式
file_patterns:
- "**/test/**"
# 忽略的写入方法(类全名#方法名)
writer_methods: []
# 忽略的 MQ destinationtopic 或 topic:tagglob
mq_destinations: []
# 检测规则
detection:
# 启用的写入模式(默认已全部开启)
patterns:
- W01 # redisUtil.insert + JSON.toJSONString
- W02 # redisTemplate.opsForValue().set + JSON.toJSONString
- W03 # stringRedisTemplate + JsonUtil.getObjectToString
- W04 # redisTemplate 直写对象
- W05 # opsForHash().put
# MQ 生产侧投递Phase M1 + M2
mq_patterns:
- MQ01 # rocketMQTemplate.syncSend
- MQ02 # asyncSend / syncSendOrderly / sendOneWay
- MQ03 # convertAndSend
- MQ04 # MessageBuilder.withPayload / Message<T>
- MQ05 # 先 toJSONString 再 send String
- MQ-K01 # kafkaTemplate.send(topic, payload)
- MQ-K02 # kafkaTemplate.send(topic, key, payload)
- MQ-K03 # kafkaTemplate.send(ProducerRecord)
- MQ-K04 # 先 JSON 序列化为 String 再 send
# W06读侧反序列化类型辅助不产生独立告警
read_hints_enabled: true
# MQ-R 读侧补强Listener / parseObject
mq_read_hints_enabled: true
# 类型推断最低置信度,低于此值标记为低置信度提示
min_confidence: 0.6
# 字段展开最大深度(防止循环引用死循环)
max_field_depth: 8
# 人工补充映射(自动推断失败或需精确指定时使用)
manual_mappings:
- id: tenant-db-content
writer_method: "jnpf.util.TenantDbContentCacheHelper#cacheSuccess"
key_pattern: "tenant:db:content:*"
value_type: "jnpf.util.TenantDbContentCacheHelper.CacheEnvelope"
description: "租户库信息缓存"
- id: attendance-base-setting
writer_method: "jnpf.attendance.service.impl.AttendanceBaseSettingServiceImpl#getStringAttendanceBaseSettingMap"
key_pattern: "fbt:attendance:base_setting:cache:*"
value_type: "java.util.Map"
description: "考勤基础设置缓存Map<String, AttendanceBaseSetting>"
# 抑制规则(已知误报)
suppressions:
- id: ignore-export-progress
key_pattern: "file:download:user:progress:*"
reason: "导出进度缓存,结构变更不影响业务读取"
# 模块过滤(可选,默认扫描全部模块)
include_modules:
- jnpf-tenant
- jnpf-ftb
- jnpf-file
- fantaibao-data-analysis
# exclude_modules: []
```
---
## 3. 配置项说明
### 3.1 enabled
总开关。默认 `true`
| 值 | 行为 |
|----|------|
| `true` | 正常执行检测(再按 `mode` / `notify` 行为) |
| `false` | 跳过检测与通知,流水线 `exit 0`(与 `notify.enabled` 无关) |
临时关闭时可仅改此项,无需删除 workflow。
### 3.2 mode
| 值 | 行为 |
|----|------|
| `notify` | 检测到变更 → 发企微 → `exit 0` |
| `block` | 检测到任意结构变更 → 发企微 → `exit 1` |
建议上线初期仍使用 `mode: notify` 观察误报情况,确认稳定后再切换:
```yaml
mode: block
```
### 3.3 notify
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `enabled` | boolean | true | 是否发企微 |
| `webhook_url` | string | `""` | 企微机器人 Webhook 完整 URL优先 |
| `webhook_env` | string | — | 兼容旧字段;值为 `http` 开头时当作 URL |
| `notify_on_clean` | boolean | false | 无变更时是否通知 |
| `title_prefix` | string | [序列化结构变更] | 消息标题前缀 |
### 3.4 ignore.key_patterns
支持 glob
- `*` 匹配单层
- `**` 匹配多层
内置/代码层常见过滤:
- 分布式锁 key配置 glob + 方法名忽略)
- 登录计数、session/token
- 琐碎 value字面量、`"1"``UUID.randomUUID()`
- 方法:`setIfAbsent` / `increment` / `delete` / `expire`
### 3.5 detection.patterns
| 模式 | 说明 | 状态 |
|------|------|------|
| W01 | `redisUtil.insert(key, JSON.toJSONString(x), ttl)` | 已启用 |
| W02 | `redisTemplate.opsForValue().set(key, JSON.toJSONString(x), ...)` | 已启用 |
| W03 | `stringRedisTemplate.opsForValue().set(key, JsonUtil.getObjectToString(x), ...)` | 已启用 |
| W04 | `redisTemplate.opsForValue().set(key, obj, ...)` 直写对象 | 已启用Phase 2 |
| W05 | `redisTemplate.opsForHash().put(key, field, obj)` | 已启用Phase 2 |
业务仓可通过只声明子集暂时关闭某些模式,例如仅保留 JSON 写入:
```yaml
detection:
patterns: [W01, W02, W03]
```
### 3.5.1 detection.read_hints_enabledW06 辅助)
| 字段 | 类型 | 默认 | 说明 |
|------|------|------|------|
| `read_hints_enabled` | boolean | true | 扫描 `parseObject` / `parseArray` / `getJsonToBean` 等,补强同文件或同 key 写入点的 value 类型 |
- **不是写入模式**:不会单独因为「多了一处 parse」而告警
- 能关联到 `redis get(key)` 时,还可补强 unresolved key
- 覆盖优先级:`manual_mappings` > W06 > 写侧 AST
- **仅补强 Redis 写入点**MQ 投递点走 `mq_read_hints_enabled`MQ-R
关闭示例:
```yaml
detection:
read_hints_enabled: false
```
### 3.5.2 detection.mq_patterns / ignore.mq_destinationsMQ
| 配置项 | 说明 |
|--------|------|
| `mq_patterns` | RocketMQ`MQ01`~`MQ05`Kafka`MQ-K01`~`MQ-K04`;默认已全部开启 |
| `mq_read_hints_enabled` | MQ-R 读侧补强Listener / parse**默认 true** |
| `ignore.mq_destinations` | 忽略 destinationglob`benchmark:*` |
企微 MQ 块:`- Topic --> ...`,并带 `> **通道**: RocketMQ|Kafka`
详见:[MQ序列化结构检测方案.md](MQ序列化结构检测实施方案.md)
### 3.6 manual_mappings
当自动推断不准确时使用。匹配优先级 **高于** 自动推断(按 `类全名#方法名` 覆盖 key 模式与 value 类型)。
| 字段 | 必填 | 说明 |
|------|------|------|
| `id` | 是 | 唯一标识 |
| `writer_method` | 否 | `类全名#方法名`,精确匹配写入点 |
| `key_pattern` | 否 | 精确 key 模式 |
| `value_type` | 否 | 强制指定 value 类型 |
| `description` | 否 | 备注 |
### 3.7 suppressions
用于屏蔽已知可接受的变更:
```yaml
suppressions:
- id: my-suppression
key_pattern: "file:download:user:progress:*"
change_types:
- FIELD_ADDED
reason: "新增字段向后兼容"
```
### 3.8 include_modules / exclude_modules
| 字段 | 说明 |
|------|------|
| `include_modules` | 非空时仅扫描列出的顶层模块;空表示全仓 |
| `exclude_modules` | 始终排除的顶层模块 |
顶层模块取路径第一段,例如 `jnpf-tenant/jnpf-tenant-biz/src/main/java/...``jnpf-tenant`
---
## 4. 环境变量 / Secret
| 变量 | 必填 | 说明 |
|------|------|------|
| `WECOM_ROBOT_WEBHOOK` | 视流水线写法 | 可将 Secret 写入配置中的 `webhook_url`,或在启动前注入 |
在 Gitea 仓库 Settings → Secrets 中配置。
---
## 5. 企微消息格式
### 5.1 结构说明
- 抬头:仓库、分支、提交、提交人、时间(不展示 mode
- 正文:按 **一个 Redis Key 一块**,展示位置、类型与前后序列化骨架
- 超长UTF-8 > 4096 字节)时按 key **拆成多条**消息依次发送
- CI 控制台另打「字段明细」(变更类型 / 位置 / 摘要),企微侧按骨架展示
### 5.2 字段高亮颜色
| 变更 | 企微颜色 | Markdown |
|------|----------|----------|
| 字段删除(标在旧骨架) | 橙色 | `<font color="warning">…</font>` |
| 字段新增 / 包装层(标在新骨架) | 绿色 | `<font color="info">…</font>` |
| 路径迁移 | 旧橙 / 新绿 | 同上 |
| key 未解析提示 | 灰色 | `<font color="comment">key 未解析)</font>` |
### 5.3 示例(已解析 key
```markdown
## [序列化结构变更] jnpf-java-cloud
> **分支**: code/redis_change_detection_v1.0
> **提交**: cedd161c → 67c8a6eb
> **提交人**: dongzi
> **时间**: 2026-07-13 16:54:17
- Key --> `tenant:db:content:*`
> **位置**: `TenantDbContentCacheHelper#cacheSuccess:92`
> **类型**: `CacheEnvelope`
> **value值由** “{"dbName":"","linkList":[{"id":""}]}”
> **变更为:** “…(仅新增/迁移字段片段带 <font color="info">绿色</font>)…”
```
实际发送时仅对改动属性片段染色:新增 → `info`(绿),删除 → `warning`(橙)。
### 5.4 示例key 未解析)
```markdown
- Key --> `req.getKey()` <font color="comment">key 未解析)</font>
> **位置**: `ClockInXxxService#export:128`
> **类型**: `List<ClockInExportVo>`
> **value值由** “{"a":""}”
> **变更为:** “…新增字段带绿色高亮…”
```
未解析时按「写入位置 + key 表达式」拆分聚合,避免多个未知 key 串在一起。
---
## 6. 推荐上线配置
业务仓默认配置:
```yaml
enabled: true
mode: notify
notify:
enabled: true
webhook_url: "" # 由流水线写入真实 Webhook
include_modules: [] # 全仓
```
---