基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
编程提效2026-10-31 05:20

用AI迁移老Java系统,先守住业务行为

dev.to · AI#Java#遗留系统#AI编程
Editor brief · 编辑速览

文章讨论将Java 8、Spring 4等遗留系统迁往新版本时,AI适用的环节、确定性工具的价值与修改前提。重点提醒:编译或启动成功不能保证业务一致,缺失测试和隐含规则可能让金额舍入等变化延后暴露。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

把 Java 8、Spring 4 的老系统交给 AI,要求直接升级到 Java 21、Spring Boot 3,代码可能编译通过,应用也能启动,但财务报表里的分币舍入已经变了。原文用这个假设场景提醒:升级成功,不能只看构建是否变绿。

作者给出的路线是先读懂系统、固定现有行为,再用确定性工具批量迁移,让 AI 处理剩下的复杂问题。对维护老项目的程序员,这套分工比一条「帮我全部升级」的提示词更有参考价值。

先让 AI 解释系统,别急着改代码

Java 8、Spring 4、大量 XML、Hibernate 的 hbm.xml,以及从 2017 年起就没更新的依赖,只是老系统的外在表现。真正拖住升级的是业务知识流失、测试缺位,以及没人知道一次修改会影响哪里。

因此,作者建议先让 Claude Code、Cursor 或 Copilot 的代理模式只读仓库,每次回答一个明确的问题:

模块之间怎样依赖?请求从哪个 controller 进入?取消订单会修改哪些表、发送哪些消息?Spring XML 中的 bean 怎样注入?数据库里的 stored procedure 又藏了哪些规则?

产物应该是模块文档、Mermaid 图和业务规则清单。核实后的内容写进 CLAUDE.md、AGENTS.md 或等效项目上下文文件,供后续会话复用。

这一步仍需人工核对。反射、外部配置和源码里看不到的约定,都可能让模型判断错误。作者声称代理一小时能完成相当于一周人工阅读的工作,但没有提供项目规模、测量方法或对照记录,应把它看作经验描述。

没有行为基线,编译通过也不能放心

读懂代码之后,作者最强调的是特征测试(characterization tests):记录系统现在的输出,让后续修改一旦改变输出就报警。这种方法也叫 golden master。

它暂时不回答业务规则是否正确,只回答升级前后是否一致。

下面的测试用脱敏后的生产订单计算运费,并与旧代码生成的基准比较:

class CalculoFreteCaracterizacaoTest {

    // 从生产环境取得并完成匿名化的真实输入。
    static Stream<Pedido> pedidos() {
        return CarregadorFixture.ler("fixtures/pedidos.json");
    }

    @ParameterizedTest
    @MethodSource("pedidos")
    void freteContinuaIgual(Pedido pedido) {
        BigDecimal frete = new CalculoFreteService().calcular(pedido);

        // 与首次运行旧代码时记录的值比较。
        assertEquals(Golden.valor("frete", pedido.getId()), frete.toPlainString());
    }
}

重点是 toPlainString():这里比较的是字符串,能够捕获 1.0 和 1.00 这样的尺度差异;直接使用 BigDecimal.equals 也会区分尺度。不过,Golden 和 CarregadorFixture 的实现没有给出,这段代码展示的是测试思路,不能直接当完整工程运行。

AI 可以辅助找分支、构造输入、批量生成测试,但必须明确禁止它顺手修复业务逻辑。所有测试都应先在旧代码上通过,再开始迁移。否则,基准本身就不可信。

特征测试保存的是现有行为,其中也可能包括现有缺陷。

尤其要覆盖金额、时间、编码和集合顺序。作者列出的典型风险包括:改写 equals、hashCode,从 Date 换到 java.time 时改变时区,以及无意依赖 HashMap、HashSet 的迭代顺序。Java 18 起默认字符集统一为 UTF-8,原先在 Windows 上按 Cp1252 工作的 new String(bytes),也可能读出不同结果。

批量改名交给 OpenRewrite,复杂判断再交给 AI

把 400 个文件中的 javax.persistence 换成 jakarta.persistence,主要需要一致性。作者建议用基于抽象语法树(AST)和类型信息的 OpenRewrite,而不是让模型逐文件自由改写。

原文配置涉及 Maven 插件 org.openrewrite.maven:rewrite-maven-plugin,配方依赖为 org.openrewrite.recipe:rewrite-migrate-java,启用:

  • org.openrewrite.java.migrate.UpgradeToJava21
  • org.openrewrite.java.migrate.jakarta.JavaxToJakarta

插件和依赖的具体版本没有填写,只留了「当前版本」的占位说明,不能照抄成可运行配置。Spring Boot 升级则使用 rewrite-spring 中的 UpgradeSpringBoot_3_x 配方族,通过 mvn rewrite:discover 查看已安装版本实际提供哪些配方。

下面两条命令分别用于预览和执行迁移:

mvn rewrite:dryRun   # 在 target/rewrite/ 生成补丁,不修改源码
mvn rewrite:run      # 应用修改

先看第一行生成的补丁,再决定如何拆分迁移。工具行为可重复,不代表补丁天然符合业务要求。

版本升级也应分步进行:Java 8 到 11 要处理 JAXB、JAX-WS、CORBA 模块移出 JDK 的影响;11 到 17 要关注 JDK 内部 API 的强封装对反射调用的影响;17 到 21 在作者经验里通常较平稳。每一步都运行特征测试,问题才容易定位。

原文还提到 Amazon Q Developer,称其可把 Java 8、11、17 项目升级到 17 或 21,并要求项目能通过 Maven 构建,Ant、Gradle 项目不在该路径内。这里没有提供产品版本或验证日期,选型时需要重新核实。

升级稳定之后,再考虑把代码写得更现代

作者估计配方能覆盖 70% 到 80% 的工作,其余部分再交给 AI:替换停留在 2016 年的废弃 PDF 库、分析编译和运行时异常、查找藏在字符串里的反射引用,以及处理没有直接替代方案的旧 API。

例如 Nashorn 在 Java 15 被移除;SecurityManager 在 Java 17 被弃用,到 Java 24 被永久禁用。这些问题需要重新设计使用方式,不能靠机械替换解决。

代理的任务应缩小到「让计费模块在 Java 17 编译通过」,然后运行构建和测试、人工审查 diff、提交,再处理下一项。作者认为,三千行的 AI diff 很容易被直接批准,真正的审查反而消失了。

迁移稳定后,才进入结构改进。原文展示了把类似 2012 年写法的 JDBC DAO,改成 record 配合 Spring 6.1 的 JdbcClient,通过 sql(...).query(Cliente.class).list() 返回结果。但 record 不可变,若调用方还在执行 setNome,就不能直接替换,必须先检查全部使用位置。

同样,pattern matching、sealed 适合特定类型结构,virtual threads 适合大量阻塞 I/O;存在这些能力,不等于每个模块都该采用。拆分单体则沿用 strangler fig,让新模块逐步接管流量,最后移除旧实现。AI 可以分析类和表的关联,模块边界仍取决于团队职责、部署方式和业务归属。

我的判断

我认同这套顺序:先建立可观察的行为基线,再推进升级。它把 AI 擅长的阅读、解释、局部重写,与工具擅长的重复变换分开,比直接要求代理完成整仓迁移更容易审查。

但原文是一套经验方法,没有展示完整迁移案例、失败率或工时对照。「模型正确率 98%、剩下 2% 出错」「AST 工具正确率 100%」也没有实验支撑。确定性工具的优势是结果更可重复、修改范围更明确,配方覆盖不足、类型解析失败或运行时配置遗漏,仍然需要处理。

特征测试也不是完整保证。它能保护已覆盖输入对应的输出,却未必捕获消息发送、事务边界和数据库写入等副作用。原文开头提醒要追踪这些影响,后面却没有给出相应测试实现,这是落地时需要补齐的部分。

此外,涉及公司源码时,作者要求核对外部 API 的数据保留、训练使用条款,以及个人数据相关的 LGPD 要求。国内团队应按自己的合同、制度和适用要求处理,不能直接套用文中的法域背景。

能拿来做什么

  • 先让代理只读分析一个模块,整理入口、依赖、数据库操作和副作用;人工确认后,再写入 AGENTS.md 或团队现有上下文文件。
  • 挑出最不能出错的五条业务流程,用脱敏真实输入建立特征测试,并确认它们在旧版本全部通过;涉及写库、消息或外部调用时,要一并核对副作用。
  • 对 Java 项目先运行 mvn rewrite:dryRun 评估补丁,再按版本跨度逐步迁移,把 AI 任务限定在能够完整审查的范围。
  • 面对前端或 Node 老项目,也可以借用「先记录行为、再分步升级」的流程;具体迁移工具需要另选,原文的 OpenRewrite 配方不能直接照搬。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
用Go与DORA指标衡量编程代理交付效果
下一篇
撤销修复再跑测试,检查AI补丁是否被覆盖

资讯速览

dev.to · AI · 2026-10-31 05:20

AI 评分 8.0 / 10

相关标签

#Java#遗留系统#AI编程

继续阅读

  • 在浏览器实时预览云端 Agent 开发结果
  • 用Go与DORA指标衡量编程代理交付效果
  • 撤销修复再跑测试,检查AI补丁是否被覆盖
  • Cursor上Anthropic扩展遭植入后门近12小时
  • 让编程代理统一三端文案与翻译键