# jar-surgeon **Repository Path**: lp_gitee/jar-surgeon ## Basic Information - **Project Name**: jar-surgeon - **Description**: No description available - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-02 - **Last Updated**: 2026-09-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # JarSurgeon — Spring Boot jar 依赖手术台 ![platform](https://img.shields.io/badge/platform-macOS%20%7C%20Windows-blue) ![tauri](https://img.shields.io/badge/Tauri-2-orange) ![react](https://img.shields.io/badge/React-19-61dafb) ![rust](https://img.shields.io/badge/engine-Rust-dea584) ![version](https://img.shields.io/badge/version-0.1.0-green) 一个 macOS / Windows 双平台的桌面工具,用于安全地**查看、对比、替换、反编译** Spring Boot fat jar(以及普通 jar)中的依赖 jar 和 class 文件。 **典型场景**:线上服务包的某个依赖有 bug,官方新版本还没发布,手里只有几个修好的 `.class` —— 不用重新打包,直接对 jar 做手术。 ## 为什么需要它 | 传统做法 | JarSurgeon | |---|---| | 解压 → 改文件 → 重新打 fat jar,嵌套 jar 压缩方式容易改错导致启动失败 | entry 级精准替换,嵌套依赖始终按 Spring Boot 要求的 Stored 方式写回 | | 手工 diff 新旧依赖,肉眼比对几百个 entry | 自动 CRC diff,新增 / 修改 / 移除三栏清单 | | 改坏了没有后悔药 | 每次写入前自动备份,一键还原 | | 想看 class 内容得先装 JDK + 反编译工具 | class 结构解析开箱即用;反编译(CFR)首次使用自动下载 | ## 功能总览 | 功能 | 说明 | |---|---| | 依赖清单 | 只读解析 zip central directory,大 jar 秒级打开;支持搜索、大小/时间/压缩方式展示、重复版本检测 | | classes 树 | 业务 class 按包路径层级展示,支持搜索(搜索结果同样保持树形) | | 依赖整体替换 | 拖入新 jar → 按 artifactId 自动匹配旧版本 → entry 级 diff 预览 → 确认替换 | | class 替换 | 拖入 `.class` 文件替换 `BOOT-INF/classes/`(或普通 jar 根路径)下的同名类 | | class 结构预览 | 纯 Rust 解析 class 文件(无需 JDK),点击 👁 查看方法/字段签名、访问标志、注解 | | class 源码反编译 | 集成 CFR 反编译器(首次使用自动下载,需本机有 Java;不可用时自动降级为结构视图),直接查看 class 的完整 Java 源码;替换确认弹窗支持源码级双栏 diff | | 依赖内 class 替换 | 选中依赖 → 右侧滑出面板查看其内部文件树 → 拖入 `.class` 完成嵌套 jar 手术 | | 版本对比 | 新旧依赖 entry 级 CRC diff(新增 / 修改 / 移除 三栏清单);class 替换确认弹窗附带成员级结构差异(方法/字段增删改) | | 健康体检 | CRC 全量校验、嵌套依赖 Stored 检查、签名检测、重复版本分组告警 | | 备份与还原 | 每次替换自动生成 `.bak`;侧栏管理备份,左键预览 / 右键还原(还原前额外留安全副本) | | 操作历史 | 会话内替换记录可追溯(jar 名 / 目录 / class 三级结构 + 替换时间),支持一键清空 | ## 下载安装 前往 [Releases](https://gitee.com/lp_gitee/jar-surgeon/releases) 页面下载对应平台安装包: | 平台 | 文件 | 说明 | |---|---|---| | Windows x64 | `JarSurgeon_*_x64-setup.exe` | NSIS 安装包;未签名,首次运行 SmartScreen 需点「仍要运行」 | | macOS (Apple Silicon) | `JarSurgeon_*_aarch64.dmg` | 拖入 Applications 即可 | ## 快速上手 1. 把服务 jar 拖进窗口(或点击「打开…」选择文件) 2. **替换依赖**:依赖清单选中目标 → 拖入新版本 jar → 确认 3. **替换业务 class**:切到「classes」标签 → 拖入 `.class` 文件 → 确认 4. **替换依赖内 class**:依赖清单点选依赖 → 右侧滑出「依赖内容」面板(左缘可拖拽调宽)→ 拖入 `.class` → 确认 5. **预览 class 结构**:classes 树或依赖内容面板中点击 👁,查看方法/字段签名与注解 6. **查看源码**:预览面板中切换到反编译视图,直接阅读 Java 源码 7. 替换后自动进入「健康体检」;需要回退时在左侧「备份」区右键还原 > 建议:替换前先停服务;替换完成后从体检结果确认无误再启动。 ## 支持的 jar 布局 - **Spring Boot fat jar**:`BOOT-INF/lib/*.jar` 依赖 + `BOOT-INF/classes/` 业务类 - **普通 jar**:class 与依赖 jar 直接位于根路径(自动探测,无需配置) ## 安全机制 - **只读检查优先**:inspect / diff 均为只读操作,不改动原文件 - **自动备份**:任何写入前先生成 `<原文件名>.bak` - **store 方式写入**:嵌套依赖 jar 始终以 Stored(不压缩)方式写回,符合 Spring Boot 嵌套 jar 加载要求 - **raw_copy 搬移**:重写归档时其余条目按原始字节搬移,不重新压缩、不改动内容 - **落盘前自检**:新归档 CRC 校验通过才替换原文件,失败即中止并保留原包 - **还原二次保护**:从备份还原前会先另存 `.pre-restore` 副本 ## 架构与 Tech Stack ``` jar-surgeon/ ├── src/ # 前端(React 19 + TypeScript + Tailwind 4) │ ├── App.tsx # 全部 UI:清单 / classes 树 / diff / 体检 / 备份 / 历史 │ ├── types.ts # 与 Rust 侧共享的数据结构 │ └── App.css # macOS 原生风格主题(SF Pro、系统蓝 #007AFF) └── src-tauri/ └── src/lib.rs # 核心引擎(Rust + zip crate,纯函数化,无系统命令依赖) ``` | 层 | 技术 | |---|---| | 桌面框架 | Tauri 2(macOS 用 WKWebView,Windows 用 WebView2,单代码库双平台产物) | | 前端 | React 19 / TypeScript / Tailwind CSS 4 / Vite 7 | | 核心引擎 | Rust + `zip` crate,零系统命令依赖 | | class 解析 | 纯 Rust 实现 class 文件格式解析(常量池 / 字段 / 方法 / 注解) | | 反编译 | CFR Java Decompiler(首次使用自动下载,需本机 Java) | **Rust 侧命令原语**(前端通过 Tauri invoke 调用): | 命令 | 职责 | |---|---| | `inspect_jar` | 解析清单(lib + classes,前缀自适应) | | `suggest_old_lib` / `diff_lib` / `replace_lib` | 依赖整体替换流程 | | `suggest_old_class` / `diff_class` / `replace_class` | 业务 class 替换流程 | | `inspect_lib_classes` / `suggest_old_class_in_lib` / `diff_class_in_lib` / `replace_class_in_lib` | 依赖内 class(嵌套 jar)替换流程 | | `verify_jar` | 健康体检(CRC / Stored / 签名 / 重复版本) | | `read_class` / `read_class_in_lib` / `read_class_file` | class 结构解析(常量池 / 字段 / 方法 / 注解,供预览与结构 diff) | | `decompile_class` / `decompile_class_in_lib` / `decompile_class_file` | class 源码反编译(CFR) | | `list_backups` / `restore_backup` | 备份管理 | ## 开发 ```bash # 环境要求:Node 20+ / pnpm / Rust stable(1.88+) pnpm install pnpm tauri dev # 本地开发调试 pnpm exec tsc --noEmit # 前端类型检查 cd src-tauri && cargo test # 核心引擎测试(含全链路替换用例) ``` ## 构建产物 ```bash # macOS .app / .dmg pnpm tauri build # Windows 交叉编译(macOS 上直接产出 NSIS 安装包) # 前置:rustup target add x86_64-pc-windows-msvc # cargo install cargo-xwin && brew install llvm PATH="$PWD/.cargo-shim:/opt/homebrew/opt/llvm/bin:$HOME/.rustup/toolchains/stable-aarch64-apple-darwin/bin:$PATH" \ pnpm tauri build --target x86_64-pc-windows-msvc --bundles nsis ``` `.cargo-shim/cargo` 是交叉编译垫片:把 tauri-cli 发起的 `cargo build` 转发给 `cargo xwin`(自动注入 lld-link 与 Windows SDK)。垫片内已处理 `CARGO` 环境变量指向真实 cargo,避免 cargo-xwin 回调垫片造成无限递归。 Windows 安装包未签名,首次运行 SmartScreen 需点「仍要运行」。 ## 已知边界 - **签名 jar**:若归档或内层依赖带签名(META-INF 下 `.SF/.RSA`),替换会破坏签名,体检会给出告警,请自行评估 - **同名类**:class 替换按短名匹配,多个包下存在同名类时,先在清单中选中目标条目再拖入即可精确指定 - **备份覆盖**:每次替换的备份都是同一个 `<文件名>.bak`,后一次会覆盖前一次(需要多版本备份链可自行改进) ## 常见问题 **Q:替换依赖内 class 后启动报 `FileNotFoundException ... %20 ...`?** 与替换无关。是启动目录路径含空格,服务的版本检查组件(如 `VersionGet`)从 URL 截取 jar 路径时未做 URL 解码导致,仅影响版本信息展示,不影响启动。把目录改成不含空格即可消除。 **Q:怎么确认替换后的包是健康的?** 看「健康体检」四项:CRC 校验通过、无「非 Stored」依赖、无意外签名变化;再实际启动一次,观察有无 `ClassNotFoundException` / `NoSuchMethodError` 等类加载错误。