# jnpf-ftb 启动时长优化方案（仅文档，不改代码）

## 1. 背景与目标
- 现象：`jnpf-ftb` 本地启动约 4-5 分钟。
- 已知线索：你通过 thread dump 观察到大量“类加载”相关活动。
- 目标：先通过配置与启动参数优化，把本地开发启动时长先压缩到 2-3 分钟以内，再决定是否做代码级改造。

## 2. 当前项目现状（基于仓内配置与日志）

### 2.1 启动链路中已确认的重阶段
1. Nacos + Dubbo bootstrap 阶段较早介入。
2. `bootstrap.yml` 中 Nacos 额外加载了多份配置：
   - `datasource.yaml`
   - `resources.yaml`
   - `system-config.yaml`
   - `frame-config.yaml`
   - `logger.yaml`
3. 启动过程中启用了 RocketMQ Stream Binder（包含 producer/consumer 绑定）。

### 2.2 日志证据（2026-05-08）
- 例 1：`14:39:29.960` 进入 Dubbo 日志，`14:39:37.108` 才完成 `Located property source`，该阶段约 7 秒。
- 例 2：`14:16:04.763` 到 `14:16:10.401`，同阶段约 5.6 秒。
- 说明：仅 bootstrap/Nacos 配置拉取就已占用可见时间，且这是“启动前段”，不是全部耗时。

### 2.3 规模与潜在类加载压力
- `src/main/java` Java 文件数：`1300`
- `src/main/resources` XML 文件数：`236`
- 其中 `*Mapper.xml`：`235`
- 结论：MyBatis Mapper 解析 + Spring Bean 扫描 + 自动配置评估的总量较大。

### 2.4 依赖结构中的“重组件”
`jnpf-ftb-biz/pom.xml` 中包含可能影响冷启动的组件（示例）：
- `spring-cloud-starter-alibaba-nacos-config`
- `spring-cloud-starter-stream-rocketmq`
- `rocketmq-spring-boot-starter`
- `netty-all`
- `arthas-spring-boot-starter`（当前 local 已关闭）
- 多个内部业务模块（示例、工作流、可视化开发、权限等）

### 2.5 启动期主动逻辑
- `DealLeaveOutUser` 使用 `@PostConstruct` 注册 Redisson Topic Listener。
- 该类会在容器初始化期参与 Bean 创建与依赖注入，对启动前半段有叠加影响。

## 3. 优化原则
1. 先量化后优化：每次只改 1-2 个变量，避免“改了很多但不知道谁生效”。
2. 优先做零代码优化：先通过 profile/启动参数/环境隔离拿到明显收益。
3. 开发态与生产态分离：本地开发优先“快启动”，生产保留完整能力。

## 4. 第一阶段（零代码）优化清单

### 4.1 建立基线（必须先做）
每次实验统一记录以下指标：
1. `T1`：进程启动到 `Located property source` 完成。
2. `T2`：`Located property source` 到 Web 服务可访问（HTTP 200）。
3. `T3`：总启动耗时（T1 + T2）。
4. Top 慢阶段说明（从日志/JFR 中记录）。

建议至少做 3 次冷启动取平均值，避免单次抖动。

### 4.2 本地 profile 裁剪（优先级最高）
目标：本地开发不需要的中间件先禁用或降级。

可优先尝试（仅本地 profile）：
1. RocketMQ 消费者关闭或延后启动（若当前开发不依赖消息消费链路）。
2. Dubbo 服务暴露/订阅按需启用，非当前调试模块尽量关闭。
3. Nacos 扩展配置按需加载，非必要配置减少本地拉取。
4. 外部 SDK（如 OCR/IM 等）仅在需要时启用。

预期收益：通常可减少 20%-50% 启动时间（视当前功能依赖而定）。

### 4.3 JVM 启动参数优化（不改业务代码）
建议先做 A/B 对比：
1. `-XX:TieredStopAtLevel=1`
   - 作用：偏向更快启动，牺牲部分长期峰值吞吐。
2. `-noverify`（仅本地开发，JDK11 需评估兼容）
   - 作用：降低类校验开销，可能缩短类加载阶段。
3. 固定堆大小避免动态扩容抖动：
   - 示例：`-Xms1g -Xmx1g`
4. 启动期诊断专用（仅采样，不建议长期打开）：
   - `-XX:StartFlightRecording=filename=ftb-startup.jfr,duration=300s,settings=profile`

说明：类加载“看起来很慢”有时是 I/O、网络等待、反射初始化导致，JFR 用来区分真实瓶颈。

### 4.4 远程依赖可达性与超时
1. 检查 Nacos/RocketMQ/Redis/Dubbo 注册中心网络 RTT 与连接超时配置。
2. 本地开发环境尽量使用同网段、低延迟节点。
3. 无法稳定连接时，设置明确的快速失败策略，避免默认长等待。

预期收益：可显著降低“偶发 4-5 分钟”这种长尾启动。

## 5. 第二阶段（小改配置/少量代码，后续可评估）
> 本阶段是建议项，当前按你的要求不实施代码修改。

1. 缩小扫描范围：
   - 精确 `@MapperScan` 与组件扫描包路径，减少无关类扫描。
2. 延迟初始化：
   - 对非关键 Bean 启用 lazy/init-on-demand。
3. 启动任务后移：
   - `@PostConstruct` 中的非关键动作改为 `ApplicationReadyEvent` 或异步初始化。
4. 模块化拆分：
   - 本地常用能力与低频能力拆分开关，减少全量依赖装配。

## 6. 推荐的执行顺序（两天可完成）

### Day 1：拿到可重复数据
1. 固化基线采样表（3 次冷启动平均）。
2. 加 JFR 采样，确认 top 慢阶段（配置拉取/Bean 初始化/Mapper 解析/网络连接）。
3. 先做“本地 profile 裁剪”第一轮（MQ + 非必要远程能力）。

### Day 2：参数组合与回归
1. 对 JVM 参数做 2-3 组 A/B。
2. 对 Nacos 扩展配置做最小集实验。
3. 形成最终本地启动模板（profile + VM options + 依赖清单）。

## 7. 验收标准（KPI）
1. 本地冷启动平均时长：从 4-5 分钟降到 2-3 分钟。
2. 启动时长 P95：不超过平均值的 1.3 倍。
3. 每轮优化都能说明“改了什么、快了多少、副作用是什么”。

## 8. 附：本次分析引用文件
- `jnpf-ftb-biz/src/main/resources/bootstrap.yml`
- `jnpf-ftb-biz/src/main/resources/application-local.yml`
- `jnpf-ftb-biz/pom.xml`
- `jnpf-ftb-biz/src/main/java/jnpf/JnpfFtbApplication.java`
- `jnpf-ftb-biz/src/main/java/jnpf/util/DealLeaveOutUser.java`
- `log/jnpf-ftb/log_info.log`

## 9. 编码与乱码建议
- 本文档请保持 `UTF-8` 编码。
- 若在 Windows 终端查看出现乱码，优先检查：
  1. IDE 文件编码是否为 UTF-8。
  2. 终端代码页是否与文件编码一致。
  3. 日志/控制台输出是否混用不同编码。
