外观
如何使用本手册
本手册面向第一次接触 antispam-private-summary 的开发者与运维。目标:让你在最短时间内回答「这个模块有几个进程、怎么起、起不来的原因是什么」。
一、先建立三个心智模型
1. 仓库 = 40 个独立部署单元的组合,不是单体应用
- 每个顶层目录(如
antispam-business-audio)= 一个 Maven 聚合工程 = 一个独立部署单元集合。 - 跨模块通信只有三种方式:Dubbo(RPC)/ Kafka(异步)/ HTTP(对外或内部服务名)。禁止类库级跨模块强耦合。
- 同一个模块内部,通常又拆成 5–8 个独立进程(各有自己的
main、Dockerfile、build.sh)。
2. 模块内部的「标准骨架」
绝大多数业务/方案模块都长这样:
<module>/
├── common/ # 公共 BO / 枚举 / 常量(类库,不部署)
├── domain/ # 实体 / DTO(类库,不部署)
├── service/base/ # MyBatis DAO + Manager + 动态数据源(类库)
├── service/business/ # ES / Redis / Kafka Producer 封装(类库)
├── facade/
│ ├── dubbo-api/ # Dubbo 接口定义(类库)
│ ├── dubbo-check-api/ # 检测类 Dubbo 接口定义(类库)
│ ├── dubbo-provider/ # 查询/管理类 Dubbo 实现 ← 独立进程
│ ├── dubbo-check-provider/ # 检测类 Dubbo 实现 ← 独立进程
│ ├── http-api/ # 查询 / 回调 / 反馈入口 ← 独立进程
│ └── http-check-api/ # 提交 / 同步检测入口 ← 独立进程
├── storage/ # Kafka 消费,结果落库/落 ES/回调 ← 独立进程
├── scheduler/ # Elastic-Job 定时扫库/归档/告警 ← 独立进程
├── console/api/ # 控制台后端(多数无 Dockerfile)← 通常独立进程
├── buildAll.sh / buildAll-arm.sh # 全量构建
└── kubernetes.yml # k8s 部署编排重要:
console/api在绝大多数模块里没有Dockerfile/build.sh,因此不会被buildAll.sh构建。看到它有启动类不代表它会部署。
3. 构建与部署的「统一范式」
bash
# 模块根:全量构建(以 private 环境为例)
bash buildAll.sh
# = git pull
# → mvn clean install -Dmaven.test.skip=true -Pprivate
# → find . -name build.sh 逐个执行:bash build.sh -c false -p false -e private
# → 每个 build.sh:mvn --pl <MODEL> -am -T 1C → docker buildx --platform linux/amd64,linux/arm64 --push
# → source ~/.zsh_private && podupdate.sh <image> <tag> # 更新 k8s Pod单进程构建:
bash
cd facade/http-check-api
bash build.sh -t <tag> -e private # -c false 可跳过二次编译buildAll.sh 遍历的是 find . -name build.sh,所以没有 build.sh 的子模块永远不会被这个脚本构建 —— 这是新人最常见的「改完不生效」原因。
二、启动逻辑的通用抽象:@Enable* 注解体系
这是读懂所有 Java 服务启动逻辑的唯一关键。启动类几乎不写逻辑,全部靠注解声明式装配:
java
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) // 关闭自动数据源
@EnableBusinessClient // → @Import(BusinessClientConfiguration):从 ZK 拉产品/Target/密钥配置
@EnableRateLimiter // → 平台限流组件
@EnableRecoverComponent // → 故障恢复(落盘重放)
@EnableI18nComponent // → 国际化
@EnableApolloConfig // → Apollo 配置中心(bootstrap 阶段拉取)
@EnableElasticJob // → Elastic-Job 调度(注册到 ZK)
@EnableCdcDataSubscribe // → CDC 数据订阅(binlog → ES)
@EnableDistributeId // → 分布式 ID(依赖 ZK)
@EnableOssClient // → NOS/S3 对象存储客户端
@EnableApolloConfig // → 配置中心
public class HttpCheckApplication {
public static void main(String[] args) {
SpringApplication.run(HttpCheckApplication.class, args); // 通常无自定义逻辑
}
}读启动类的三步法:
- 看
exclude:exclude = DataSourceAutoConfiguration.class意味着这个进程不连数据库(或数据源由自定义配置类接管)。很多「为什么它连不上库」的困惑源于此。 - 看
@Enable*列表:每一个EnableXxx都对应一个能力(Kafka 消费 / Dubbo 注册 / 定时任务 / 分布式 ID / OSS …),列表即「启动时会拉起哪些组件」。 - 看自定义
@EnableXxxAutoConfiguration:模块自研的注解,通常@Import(XxxConfiguration.class),而XxxConfiguration里的@ComponentScan+@MapperScan决定了哪些包被扫描 —— 包路径写错,服务能起来但 Bean 缺失。
三、启动钩子(容易漏看的启动期行为)
| 类型 | 典型用途 | 例子 |
|---|---|---|
@PostConstruct | 启动期全量加载缓存/词表/名单 | ImageConfigSyncService.init()、ListFullSyncService、BusinessCacheManager.init() |
ApplicationListener<ContextRefreshedEvent> | 容器刷新完成后预热 | ContextRefreshedEventListener(keyword、rule、liveaudio) |
ApplicationRunner / CommandLineRunner | 启动后执行一次性任务 | RedisDelayTask(antispam-cms 恢复延迟队列)、FlywayApplication(数据库迁移) |
SmartLifecycle | 控制启停顺序 | StorageSmartLifecycle(business-video/livevideo) |
QosApplication(@QosRegister) | 上下线摘流量 | YidunQosApplication.doOffline() 会 pause/stop Kafka 容器再 sleep |
@Scheduled / @ElasticJobConf | 周期任务 | 各模块 scheduler 单元 |
doOffline()里的Thread.sleep是关键:优雅下线要等这个时间,所以 k8s 的terminationGracePeriodSeconds必须大于它,否则发布时被强杀、消息丢失。
四、模块文档的固定结构
每篇模块文档都是同一套结构,便于横向对比:
- 一句话定位 + 架构分层
- 可部署服务清单(目录 / artifactId / 镜像名 / 端口 / 类型 / 有无 Dockerfile / 是否真的部署)
- 启动顺序(同模块内推荐次序 + 理由)
- 逐服务启动逻辑(启动类、exclude、@Enable*、Configuration、启动钩子)
- 启动前置依赖(按先后,标注阻塞 / 弱依赖)
- 启动参数与 Profile(
-Dspring.profiles.active、maven profile、JAVA_OPTS、base image) - 启动期踩坑
- 跨模块前置(启动前必须已在运行的其它模块服务)
五、术语约定
| 术语 | 含义 |
|---|---|
| 部署单元 | 有独立 main + Dockerfile/build.sh 的子模块,对应一个容器进程 |
| 阻塞启动 | 该依赖不可用时进程起不来(抛异常退出) |
| 弱依赖 | 该依赖不可用时进程能起来,但功能降级或运行期报错 |
| Sharding Provider / Customer | antispam-rule 的分片数据发布方 / 订阅方 |
| 未发现 | 在当前仓库快照内未检索到该事实,不代表不存在 |
| 推断 | 由脚本/命名规律反推,需以真实流水线为准 |
下一步:全局启动顺序与依赖链 →