CHARLIE SAYS

查理如是说
DATE 2026-08-24
THEME
SERIES / JHIPSTER / P-237 · JHipster 项目开发

JHipster 开发 22:升级策略——JHipster 版本怎么跟

从 JHipster 6 跟到 9.x(Spring Boot 4、Java 21、Angular 21),我们平均每 12-18 个月做一次大版本跨越,小版本则随安全补丁随时跟进。这篇把这个过程方法论化:版本节奏怎么理解、成本从哪来、三条升级路线怎么选、哪些纪律能让下次升级便宜一半,以及什么时候我们决定不升了。

版本节奏与”要不要跟”

JHipster 大体维持半年一个 major 的发布节奏(8.x 到 9.x 间隔约一年半,中间穿插大量 minor/patch)。major 意味着生成模板大改:9.x 这次就带了生成器 TypeScript 重写、yeoman v8、Spring Boot 4 与 Java 21 强制。跟不跟的判断框架:

情形建议
生命周期 > 2 年的项目major 最多跳一个版本(6→8 可以,6→9 谨慎),否则积压成本指数增长
有安全 CVE 压力(Spring/依赖)优先升级,或至少做依赖热修
团队正在大规模改业务代码错峰,业务封版后再升
项目进入纯维护期跟安全 patch,major 可冻结,但要写进决策记录

我们的教训:JHipster 7 → 8 拖了一年半,结果 Spring Boot 3 的 Jakarta 命名空间迁移和 JHipster 8 的改动叠加,diff 大到 review 了一周。升级成本随跨越版本数超线性增长,宁可小步多次。

升级成本从哪来

生成代码不是普通依赖,升级时它的成本结构特殊:

  1. 生成代码冲突:你手改过的生成文件,重新生成时必然冲突。这是最大头,也是第 23 篇”不改生成代码哲学”存在的原因。
  2. 依赖 breaking:Spring Boot major(如 3 的 Jakarta、4 的部分 API 收紧)、Angular major(21 的 Zoneless 迁移收尾)、Node 版本要求(9.x 要 Node 22)。
  3. 配置项迁移application.yml 里的配置键随 Spring Boot 版本改名/废弃,JHipster 自身的 jhipster.* 命名空间也会调整。
  4. 构建工具链:Maven 3.9、前端构建链、Docker 基础镜像的同步更新。

其中 1 完全可控,2/3/4 社区已趟过、有 release notes 与迁移指南可抄。

三条升级路线

路线一:jhipster upgrade 子生成器

npm install -g generator-jhipster@9.x
cd myapp
jhipster upgrade --from 8.7.0 --to 9.0.0

原理:工具把你的项目按新旧两个版本各生成一份(利用 .yo-rc.json.jhipster/*.json),三方合并生成代码的 diff,再把这份 diff 应用到你的分支上,最后留一个待解决的冲突清单。适合:生成代码改得少、跨一个 major 以内的项目。产出是一个巨大的 PR,review 压力集中。

路线二:migrate blueprint

npm install -g generator-jhipster-cli
jhipster migrate

官方的 generator-jhipster-migrate blueprint 扫描项目与最新模板的差异,按文件给出”接受新模板 / 保留本地版本 / 手工合并”的交互式选择,增量式走完整个升级。适合:跨多个 major、或想分模块分批推进的大项目。9.x 重写后的生成器对这条路支持更好,我们 8→9 就是用它分三次 PR 走完的。

路线三:手动 diff 重生成

最朴素也最可控:新目录里按 .yo-rc.json 用新版本生成一份”纯净工程”,然后逐目录与老工程 diff:

mkdir /tmp/myapp-fresh && cd /tmp/myapp-fresh
cp $OLD/.yo-rc.json .
cp -r $OLD/.jhipster .
jhipster --with-entities        # 按事实源整体重生成
diff -ru $OLD/src /tmp/myapp-fresh/src | less

适合:升级同时要清理历史包袱、或有定制 blueprint 的团队。成本最高但每一步都在掌控中。

维度upgrade 子生成器migrate blueprint手动 diff
适用跨度≤1 个 major跨多 major任意
交互粒度一次性大 PR按文件增量完全自定义
人工投入中低
风险冲突堆积 review 困难依赖 blueprint 更新流程靠人,易漏
我们的使用频率早期常用当前主力半年一次的大清理

事实源:升级便宜的根因

三条路线全部依赖同一组”再生事实源”:

.yo-rc.json          # 应用级选项:技术栈、认证方式、包名、语言
.jhipster/
  Customer.json      # 每个实体的字段、关系、DTO/服务层选项
  OrderItem.json
myapp.jdl            # (可选)等价 JDL 表达,随生成维护

只要它们与代码同步,“用新版本重新生成整个应用”永远是可行操作,升级就只是 diff 管理问题。反之,如果实体是在老版本里生成后 .jhipster/*.json 被删了或忘了随字段修改更新,生成器就再也还原不出当前代码,升级立刻退化为纯手工迁移。我们的纪律:

  • .yo-rc.json.jhipster/ 全部进 git,实体结构变更必须同步改 JDL/JSON 后重新生成(jhipster entity Customer --single-entity),而不是直接改生成代码;
  • review 时把”改了生成文件却没改事实源”视为缺陷。

锁定生成代码的修改策略

升级冲突量 ≈ 你改过的生成文件数。策略按侵入度排序:

  1. 不动:业务逻辑放新包/新模块(第 23 篇),生成文件保持出厂状态。
  2. 标记性扩展:必须改的生成文件(如 SecurityConfiguration 加一条规则),改动集中、注释标记 // CUSTOM:,升级时按标记搬运。
  3. fork 模板:改动面大且通用 → 做成 blueprint(第 24 篇),让生成器原生产出你要的样子。

我们统计过 8→9 升级:手改生成文件 23 个的模块 review 加迁移花了 6 人日;同期一个几乎零手改的模块只花 1 人日。差距就是哲学的差距。

升级前的 git 准备与回归测试

标准流程,缺一不可:

# 1. 干净起点:main 合并完所有在途分支
git checkout main && git pull
# 2. 独立升级分支
git checkout -b upgrade/jhipster-9
# 3. 打 tag 便于回退对照
git tag pre-jhipster-9
# 4. 跑升级工具(任选路线)
# 5. 逐文件解决冲突后,全量回归
./mvnw verify        # 后端单测 + Testcontainers 集成测试(第 17 篇)
npm run e2e          # Cypress 端到端

回归底线:测试套件是升级的保险绳,覆盖不足的项目先补关键路径的集成测试再谈升级(第 17 篇的分层测试在这时兑现价值)。数据库侧还要做 Liquibase 前滚演练(第 7 篇)。

小版本与补丁怎么跟

major 之外,minor/patch 的跟进策略我们固化为两条流水线:

类型触发时限动作
安全 patch(CVE High+)依赖扫描告警3 个工作日只升受影响依赖,mvn dependency-management 锁定,走热修分支
JHipster minorrelease notes下个迭代随常规迭代合并,重生成 diff 通常很小

配套一个 CI 对账任务:每天比对本地 package.json/pom.xml 与 JHipster 当前 minor 的依赖清单,输出漂移报告。避免”生成器停在 9.0、手工依赖悄悄升到 9.2 等价版本”的隐性漂移——下次升级时这些漂移全部变成额外 diff。此外团队约定所有人用同一生成器版本npm ls -g generator-jhipster 对齐),本地 9.0 与 9.1 生成的实体文件细微差异会在 review 里制造噪音。

何时放弃升级

三种情况我们认真评估过”不升”:

  • 项目剩一年维护期:冻结版本,只做依赖安全热修,把升级预算留给接替系统;
  • 生成代码已被改得面目全非:事实源失效,重生成等于重写——先做”生成代码回归出厂”的重构(成本另计),否则升级无解;
  • 技术栈分叉:例如前端早已迁出 Angular 换成别的方案,只升后端,此时把 JHipster 当普通 Spring Boot 工程对待,只跟 Spring Boot 版本。

放弃不是失败,是把升级成本和收益摆上台面后的理性决策——前提是决策写进 ADR,半年后复审一次而不是永远搁置。

小结

  • 半年一个 major 的节奏下,升级要”小步、跟紧、错峰”;跨越版本越多成本越超线性。
  • 三条路线按项目健康度选:upgrade 子生成器适合小跨度、migrate blueprint 是当前主力、手动 diff 兜底大清理。
  • .yo-rc.json.jhipster/*.json 是再生事实源,与代码同步是升级便宜的根本前提。
  • 生成代码少改、标记改、或固化进 blueprint,是给未来升级送的最好礼物。

系列导航

← 设计模式 022:观察者(Observer) 目录 算法 023:图:遍历(BFS & DFS) →
← 返回文章列表