ddsha441981/wiredoctor

GitHub: ddsha441981/wiredoctor

WireDoctor 是一款零侵入的 Spring Boot 运行时诊断与架构分析工具,能够自动检测循环依赖、启动瓶颈、幽灵 bean 并提供交互式可视化报告与架构回归防护。

Stars: 0 | Forks: 0

# 🩺 WireDoctor WireDoctor 是一款针对 Spring Boot 的运行时诊断与架构分析工具。它作为一个自动配置 starter 工作,直接挂钩到真实且已解析的 Spring `ApplicationContext`,无需任何构建工具更改。**零侵入、零 dashboard server、纯洞察。** 请参阅下方的[支持版本](#-supported-versions)表——其中列出的每一个组合都已在每次构建的 CI 中得到验证。 ## ✨ 功能 ### v0.6.0 新特性 - 👻 **Ghost Bean Detector**:哪些 bean 耗费了你的启动时间和内存,却从未执行任何操作?分为两个阶段,两种信任姿态。**阶段 1(被动,始终开启):** `ghostCandidates` 报告部分交叉比对了三个信号——被急切实例化 ∧ 零传入依赖 ∧ 无可检测入口点(`@Controller`、`@Scheduled`/`@EventListener` 持有者、`CommandLineRunner`、消息监听器等)——这是一个比原始孤儿列表严格更强的信号,但依然被标记为 `confidence: LOW` 并附带诚恳的免责声明。**阶段 2(可选,用于开发/预发环境):** `wiredoctor.ghost-tracking.enabled=true` 会将符合条件的用户 bean 包装在一个轻量级的首次调用计数代理中(首次调用后约 180 纳秒/次调用——只需一个 `AtomicBoolean`,不计时,不记录参数),并在关闭时写入 `wiredoctor-ghost-report.json`:包含 touched / untouched / untrackable。默认情况下,用于追踪的 `BeanPostProcessor` **永远不会被注册**——回归测试在每次构建中都证明了其被动性承诺。可通过 `/actuator/wiredoctor/ghosts` 实时查看。从不断言“未使用”——仅说明“在此运行期间从未被调用”。→ **[Ghost Detector 指南](docs/ghost-detector.md)** [WireDoctor] Ghost tracking summary: 38 touched, 3 untouched, 6 untrackable ('untouched' 意指在本次运行期间未被调用——并非'未使用') ### v0.5.0 新特性 - 🩺 **Upgrade Guard(Autoconfig Condition Diff)**:升级了 Spring Boot,却因为某个自动配置停止生效导致某个功能悄悄失效了?WireDoctor 现在会将 Spring Boot 的 **condition evaluation report** 快照存入你的 baseline 中,并在多次构建之间对其进行差异对比——因此任何 `matched → notMatched` 的翻转都会被自动捕获。你的 bean diff 已经展示了消失的*是什么*;而 condition diff 则展示了**为什么**,并附带确切的 `@ConditionalOnBean`/`@ConditionalOnClass` 消息。在 CI 中通过 `wiredoctor.fail-on=condition-changed` 对其进行拦截(可与 `new-cycle` 组合使用)。已在 Spring PetClinic(Boot 4.1)上验证——排除某个 autoconfig 后,直接暴露了该翻转*以及*它触发的下游级联效应。→ **[Upgrade Guard 指南](docs/upgrade-guard.md)** [WireDoctor] Baseline Diff (vs wiredoctor-baseline-default.json): - Conditions: 2 changed | 0 added | 7 removed - CONDITION CHANGED: JacksonAutoConfiguration (matched -> excluded) - CONDITION CHANGED: JacksonJsonHttpMessageConverterConfiguration$... (matched -> notMatched) 向后兼容:v0.5.0 之前的 baseline(无 condition 数据)会优雅地跳过 condition diff——拦截器永远不会因此触发。 ### v0.3.0 新特性 - 💡 **打破循环的 @Lazy 建议**:当检测到循环时,WireDoctor 不仅会报告它——还会告诉你如何修复它。`lazySuggestions` 报告部分(以及按排名显示的控制台摘要)列出了如果标记为 `@Lazy` 即可打破循环的 bean——排序优先考虑打破的循环数,其次是影响范围最小(依赖它的下游 bean 最少): [WireDoctor] @Lazy Suggestions to Break Cycles: 1. Make 'alphaBean' @Lazy (breaks 1 cycle(s), impacts 1 bean(s)) 2. Make 'betaBean' @Lazy (breaks 1 cycle(s), impacts 1 bean(s)) - 📐 **架构异味指标**:在*实时、已解析*的 bean 图谱上计算的经典架构健康度指标——即 Spring 实际装配的内容(代理、条件配置、profile),而非源码中声明的内容。`smells` 报告部分包括前 10 大 **fan-in 热点**(耦合 / God Object 异味)、前 10 大 **fan-out 热点**(Shotgun Surgery 异味),以及超过 Martin 的**不稳定性**阈值的 bean(`I = Ce/(Ca+Ce) ≥ 0.8`)。HTML 报告中的图节点现在按 fan-in 大小调整——点越大,依赖它的 bean 就越多。 - 🏋️ **针对大型应用的强化**:已通过包含 5,000 个 bean 的合成上下文进行验证。当超过 `wiredoctor.max-graph-nodes`(默认为 2000)时,序列化后的图谱将截断为按 fan-in 排名靠前的 Top-N 个 bean(循环成员始终保留),并附带诚恳的 `graphTruncated` 元数据和 HTML 警告横幅。分析部分——循环、异味、关键路径、baseline diff——始终在完整的图谱上运行;仅对序列化视图进行截断。 ### v0.2.0 新特性 - 🛡️ **架构回归防护**:像对待架构的 lockfile 一样提交 `wiredoctor-baseline.json`,并通过 `wiredoctor.fail-on=new-cycle` 在**有人添加了 bean 循环时让你的 PR 失败**。完全可选,未配置 baseline 时会优雅降级。→ **[CI 拦截指南](docs/ci-gating.md)** - ⛓️ **启动关键路径**:阻碍你启动过程的、基于实例化加权的最长依赖链——`criticalPath` 报告部分和控制台摘要展示了你的就绪时间实际上取决于哪条 bean 链(基于实例化加权的近似值;不对并行初始化进行建模)。 - 📦 **真正的自包含 HTML**:vis-network 图形库已打包并在生成时内联到 `wiredoctor-report.html` 中——该报告可以完全离线渲染。 ### 自 v0.1.0 起 - 🕸️ **交互式 HTML 可视化工具**:自动生成 `wiredoctor-report.html`(一个单文件、无 React、基于 Vis.js 物理网络图的报表),以便直接在你的浏览器中进行架构可视化。该报告完全自包含——vis-network 图形库在生成时已打包内联,因此可以完全离线渲染。 - ⏱️ **启动耗时**:在生命周期的早期通过 `BufferingApplicationStartup` 接入 `ApplicationStartup`,以测量并报告确切的 bean 实例化时间,无需依赖繁重的反射启发式算法。 - 🔗 **依赖图分析**:直接挂钩 `ConfigurableListableBeanFactory.getDependenciesForBean` 以查看完全解析后的依赖图。 - 🔄 **循环依赖检测**:在 bean 图谱上运行 Tarjan 的 SCC 环路检测器,以发现结构设计上的异味,即使 Spring 通过代理/setter 解决了它们。 - 🎭 **代理开销计数器**:扫描你的 bean 图谱中的 CGLIB 和 JDK 代理(例如 `@Async`、`@Transactional`),以暴露隐藏的间接寻址层。 ## ✅ 支持版本 完整的测试套件会在 CI 中针对此矩阵运行([compat.yml](.github/workflows/compat.yml));下表反映的是实际通过的状态,而不是我们希望它能起作用的组合: | Spring Boot | Java 17 | Java 21 | Java 25 | |-------------|:-------:|:-------:|:-------:| | 2.7.x | ✅ | ✅ | ✅ | | 3.3.x | ✅ | ✅ | ✅ | | 3.5.x | ✅ | ✅ | ✅ | | 4.0.x | ✅ | ✅ | ✅ | 注意: - **最低要求为 Boot 2.4**:启动耗时功能需要 Boot 2.4 中引入的 `BufferingApplicationStartup`。比 2.7 更早的版本未经 CI 验证——它们可能可以运行,但你需自行承担风险。 - 处于受测版本之间的 Boot 版本线(3.0–3.2、3.4)预计可正常工作,因为 WireDoctor 仅使用稳定的 `spring-context` / `spring-boot` API,但只有列出的版本线才附带 CI 保证。 - WireDoctor 本身编译为 **Java 17** 字节码,因此即使在 Boot 2.7 上,Java 8/11 应用程序也无法加载它。 ## 🚀 如何使用 只需将 `wiredoctor-autoconfigure` 依赖项添加到你的 Spring Boot 项目中。 **Maven:** ``` io.github.ddsha441981 wiredoctor-autoconfigure 0.6.0 ``` **Gradle:** ``` implementation 'io.github.ddsha441981:wiredoctor-autoconfigure:0.6.0' ``` WireDoctor 会在应用启动时自动运行,生成一份 JSON 报告(`wiredoctor-report.json`)以及一个交互式 dashboard(`wiredoctor-report.html`),并在标准的 SLF4J 日志中打印清晰的诊断摘要。 ### ⚙️ 配置(可选) 默认情况下,WireDoctor 会自动从“Orphan Beans”列表中过滤掉内部基础架构包(如 `org.springframework`、`java.`、`org.apache` 等),以减少干扰。 如果你想显式定义哪些包应该被扫描以查找孤儿 bean,你可以在你的 `application.properties` 中配置 `wiredoctor.scan-packages`: ``` # 单个 package wiredoctor.scan-packages=com.yourcompany.app # 多个 package(逗号分隔) wiredoctor.scan-packages=com.yourcompany.app,io.yourteam.service # 配置保存 HTML 和 JSON 报告的路径(默认:project root) wiredoctor.output-path=/path/to/your/reports # 自定义在实例化时将 bean 标记为“slow”的阈值(默认:100ms) wiredoctor.slow-bean-threshold-ms=50 # --- Architectural Regression Guard(v0.2.0,opt-in) --- # 已提交的 architecture baseline 路径;启用 diff wiredoctor.baseline=wiredoctor-baseline.json # 使用此选项运行一次以创建/刷新 baseline(从不 diffs 或 gates) wiredoctor.baseline-write=true # CI gate:当出现不在 baseline 中的 cycle 时启动失败 wiredoctor.fail-on=new-cycle # --- Large-application graph cap(v0.3.0) --- # 超过此数量的 bean 时,SERIALIZED graph(JSON + HTML 视图)将被限制为按 fan-in 排序的 # top-N(cycle 成员始终保留),以便报告保持可审查且 # 浏览器不会卡死。分析本身(cycles、smells、critical path、 # baseline diff)始终在完整 graph 上运行。0 = 无限制。默认值:2000。 wiredoctor.max-graph-nodes=2000 # --- Ghost tracking(v0.6.0,opt-in — 仅限 dev/staging) --- # 将符合条件的 user beans 包装在一个轻量级的 first-touch 计数代理中。默认 OFF: # 如果没有此属性,tracking BeanPostProcessor 根本不会被注册。 wiredoctor.ghost-tracking.enabled=true # 从不包装的 Beans(报告为 untrackable:excluded,从不静默隐藏) wiredoctor.ghost-tracking.exclude=legacySoapClient,nativeBridge ``` 有关“因为新增 bean 循环而导致 PR 失败”的完整工作流,请参阅 **[CI 拦截指南](docs/ci-gating.md)**。 ### 🛑 生产环境安全(禁用 WireDoctor) WireDoctor 默认是启用的。如果你意外地将该依赖留在了生产构建中,你可以通过以下设置完全禁用分析器,以防止其运行、写入报告或暴露 bean 结构: ``` # application-prod.properties wiredoctor.enabled=false ``` 关于报告暴露了哪些内容、如何处理它们,以及 WireDoctor **纯离线**的网络行为(其所在的 JVM 不进行任何网络 I/O),请参阅 **[安全态势指南](docs/security-posture.md)**。 ## 🔬 认知诚恳度与已知局限性 与任何静态/运行时分析工具一样,WireDoctor 更倾向于诚恳的启发式方法,而不是虚假的确定性: 1. ⚡ **AOT / GraalVM Native Image 支持:** 目前,WireDoctor 仅为**传统的 JVM 模式**设计。Spring Boot 3+ AOT 处理从根本上改变了 bean 的实例化方式。在 Native Image 下运行此工具未经测试,并且可能会产生不完整的数据。 2. 👻 **Orphan Bean 启发式检测(弱信号):** 该工具会报告“Orphan Beans”(具有 0 个传入依赖的 bean)。这是一种**启发式方法,并不保证**该 bean 未被使用。通过 `ApplicationContext.getBean()`、事件监听器或定时任务动态访问的 bean 将显示为“orphaned”。自 v0.6.0 起,`ghostCandidates` 部分对此进行了细化(入口点检测过滤掉了控制器/监听器/运行器),而可选的 ghost 跟踪可测量实际的调用情况——但即使是被跟踪为“untouched”的 bean,也仅仅意味着*在此运行期间未被调用*,绝不能直接等同于“未使用”。 3. 💥 **结构性循环与崩溃性循环:** 如果 Spring 遇到了*无法解析*的循环(例如,构造器到构造器),应用程序会在 WireDoctor 报告它之前崩溃(`BeanCurrentlyInCreationException`)。WireDoctor 检测的是*已成功解析*的循环(通过 setter 注入或代理),这些循环会静默执行。这些会被作为结构设计异味报告。 4. 🙈 **早期引用循环盲点(`allow-circular-references=true`):** 循环检测使用了 `getDependenciesForBean()`,这可能无法捕获通过 Spring 的早期引用机制(三级缓存 earlySingletonObjects 途径)解析的循环。只能检测到显式的 `@DependsOn` 以及完全注册的构造器/setter 依赖。某些被静默解析的循环可能无法被报告。 5. 🔭 **已测试的 Bean 作用域:** 该分析器主要针对 `Singleton` bean。`Prototype` bean 或复杂的 `FactoryBean` 结构可能无法在依赖图中完全映射出来,除非它们在运行时被懒加载实例化。 ## 🔮 路线图(v0.7.0 及以后) 已发布:**v0.4.0**(企业级适配)、**v0.5.0**(Upgrade Guard — autoconfig condition diff),以及 **v0.6.0**(Ghost Bean Detector — 被动候选项 + 可选的首次调用跟踪)。接下来: 1. 💰 **Cost Guardian (v0.7.0):** *启动耗时和慢加载 bean 回归——将导致启动变慢的 PR 与 CI 失败关联起来,围绕 Kubernetes 冷启动成本进行构建。* 2. 🏁 **v1.0.0 — API 及 schema 冻结 + Maven Central 发布:** *报告 schema 稳定(所有部分现已发布),发布至 Maven Central,进行发布。* 已舍弃(刻意为之):**内存占用估算**——诚恳的单 bean 堆内存数值需要 Java Agent;浅层 size-of 是一个正确性陷阱。Ghost Detector 回答了同样的潜在问题(“哪些 bean 正在浪费资源?”),而不会在字节数上撒谎。 ## 👤 作者 **Deendayal Kumawat** * 📧 **Email:** [deendayal_kumawat@hotmail.com](mailto:deendayal_kumawat@hotmail.com) * 💼 **LinkedIn:** [deendayal-kumawat](https://www.linkedin.com/in/deendayal-kumawat/) * 🐙 **GitHub:** [ddsha441981](https://github.com/ddsha441981) * 𝕏 **X (Twitter):** [@ddsha44198](https://x.com/ddsha44198) * 📝 **Medium:** [@ddsha441981](https://medium.com/@ddsha441981) * 📦 **Maven Central:** [io.github.ddsha441981](https://mvnrepository.com/artifact/io.github.ddsha441981) * 🦀 **Crates.io:** [ddsha441981](https://crates.io/users/ddsha441981) * 🐳 **Docker Hub:** [ripdedup](https://hub.docker.com/u/ripdedup) ### 📚 研究论文 *Kumawat, D. (2026). Project Lethe: Bio-Inspired Autonomous Edge Intelligence via Sub-Microsecond Continual Learning and Active Forgetting (4.2.0). Zenodo.* 🔗 [https://doi.org/10.5281/zenodo.20531995](https://doi.org/10.5281/zenodo.20531995)
标签:JS文件枚举, Spring Boot, 后台面板检测, 启动诊断, 域名枚举, 性能监控, 架构分析