技术

我用 Eclipse 的核心技术,给 AI 写了一个 Java 启动器

最近做了一个开源工具,叫 joLink。
它通过 MCP 接入现有的 AI 编程助手,提供 Java 增量编译、测试、应用启动、热更新和调试能力。底层用到了 Eclipse JDT ,不过不需要打开 Eclipse ,也不需要让 AI 操作 IDE 界面。
做它的想法很简单:我们在 IDE 里已经习惯了“改完接着跑”,我想把这种开发体验也提供给 Agent 。
目标:让 AI 更快、更顺手地运行自己写的代码

让 Agent 修改 Java 代码,再启动项目、跑单元测试,已经不是新鲜事了。
我更关心的是后面这段过程:
修改代码 → 运行测试 → 发现问题 → 继续修改 → 再次运行一个需求通常不止执行一次。第一次实现遗漏了边界,补一下;测试发现行为不对,再改一下;接口结果符合预期了,还要检查有没有影响其他功能。
AI 可以很快写完一段代码,但接下来仍然需要等待编译、启动和执行结果。如果每次只是小改动,却要重复做很多准备工作,那么几轮下来,等待就成了开发过程里很明显的一部分。
joLink 想做的,就是把这段反复“修改—运行—排查”的过程接起来,减少重复工作,让 Agent 尽快拿到下一步判断所需要的结果。
下面先看实际过程,再讲它是怎么实现的。
迅速:对比一次“测试—修改—再测试”

这次使用的是 CodeBuddy 客户端,模型为 DeepSeek-V4.1-Flash-1017 官方 api。
示例项目:JTS Topology Suite,固定版本 1.20.0,只运行 modules/core 模块中的 org.locationtech.jts.geom.EnvelopeTest。
固定提交:6e95fe82feb986a7aa657f4ffa406d8c290af509。
运行环境:macOS 、Zulu JDK 17.0.16 、Maven 3.9.11  joLink 0.1.0a10。。
这个模块本轮参与编译的源码包括 612 个生产文件和 369 个测试文件,共 981 个文件。
这次模拟一次小范围重构:先运行已有的 17 项测试,再把 Envelope.java 中的 getWidth() 做等价改写,保持功能不变,然后运行同一组测试。两轮之间只改了下面这一处,测试文件没有修改:
public double getWidth() {-  if (isNull()) {-    return 0;-  }-  return maxx - minx;+  return isNull() ? 0.0 : maxx - minx; }两组使用相同的代码起点、修改和测试。一组通过 Maven 执行,另一组通过 joLink 执行。依赖提前准备好,首次执行所需的构建准备也计入时间。
先通过 Maven 执行

让 Agent 先运行目标测试,取得第一次结果,再应用上面的改动,执行同一条 Maven 命令。两轮之间没有执行 clean。
mvn -B -ntp -Dstyle.color=never \  -f modules/core/pom.xml -Dtest=EnvelopeTest test第一次执行用了 8.472 秒,编译 612 个生产文件和 369 个测试文件,17 项测试全部通过。

修改一个生产文件后,再次执行用了 8.123 秒。日志仍然记录了 612 个生产文件和 369 个测试文件的重新编译,17 项测试全部通过,Checkstyle 也正常执行。

再通过 joLink 执行

同样的测试和修改,这次由 Agent 调用 java_fast_test。
第一次执行需要准备项目模型和编译工作区;修改代码后,再运行同一组测试。
首次执行总耗时 6.268 秒,其中工具报告的编译耗时为 2.1433 秒,编译了 981 个源文件,17 项测试全部通过。首次工作区准备已经计入总耗时。

应用相同改动后,第二轮总耗时降到 546.1 毫秒,其中编译耗时 163.1 毫秒,只重新编译了 1 个源文件,17 项测试仍然全部通过。

把两轮结果放在一起:
执行阶段Maven 总耗时joLink 总耗时第一次执行,包含首次构建准备8.472 秒6.268 秒修改代码后的第二次执行8.123 秒0.5461 秒两轮合计16.595 秒6.8141 秒第二轮的编译部分单独列出来:
第二轮编译MavenjoLink实际重新编译的源文件数981 (生产 612 +测试 369 )1编译耗时日志未提供纯编译耗时163.1 毫秒测试结果17 项全部通过17 项全部通过同样只修改一个生产文件,第二轮执行从 8.123 秒降到了 0.5461 秒,少了约 7.58 秒,执行耗时减少约 93%。
把首次准备也算上,两轮合计从约 16.6 秒降到了约 6.8 秒。
编译范围的区别很直接:Maven 这一轮仍然重编译了 981 个源文件,joLink 只重新编译了改动的 Envelope.java。测试没有省略,两边每轮都实际执行了 17 项测试。
时间取自这次截图中的工具自身报告:Maven 为 Total time,joLink 为 total_ms,不包含模型思考和客户端交互时间。Maven 两轮都保留了 Checkstyle ,因此这里比较的是两条定向测试执行路径的总耗时,不是纯编译器的速度比。
这里我最关心的不是“什么都不改,再跑一次”,而是代码真的变了以后,下一轮验证需要付出多少成本。
这就要说到 joLink 里面很重要的一部分:增量编译。
什么是增量编译,为什么值得专门讲?

我们平时用 IDEA 、Eclipse ,改完代码就点运行,很少专门关注:这一次,究竟编译了哪些文件?
Java 源码修改以后,需要生成新的编译结果,程序和测试才能执行修改后的逻辑。
假设一个项目里有几千个 Java 文件,这次只改了 OrderService 中的一段金额计算逻辑。
如果这次修改触发了整个模块重新编译,那么大量没有变化、也没有受到影响的源码,就会再做一遍相同的工作。
增量编译的目的,就是避免这类重复劳动。
第一次构建时,建立编译产物和构建状态。下一次发生修改时,根据源码变化及其影响范围更新编译结果,其余仍然有效的产物继续使用。
可以这样理解:
全量编译:修改一部分代码→ 重新编译全部源码→ 运行测试增量编译:修改一部分代码→ 判断哪些代码受到了影响→ 更新需要重新编译的部分→ 复用其他编译结果→ 运行测试它也不是简单地“只编译你保存过的那个文件”。
比如,只修改一个方法内部的计算逻辑,影响范围可能很小;但如果修改的是一个接口的方法签名,依赖这个接口的其他代码也可能需要重新编译。
增量编译处理的是“这次修改影响到的范围”,不只是“这次手动改过的文件”。
joLink 怎样使用这套能力?

joLink 先通过 Maven / Gradle 获取项目的源码目录、依赖、编译配置等信息,再建立一个持久的 Eclipse JDT 工作区。
后续修改时,由 JDT 的 Java Builder 跟踪源码变化和依赖影响,复用未变化的输出,再把编译结果交给测试或应用运行。工作区和构建状态保存在磁盘上,不只存在于某一轮对话或某一次命令里。
关键不只是留下 .class 文件,而是保留继续进行增量构建所需的状态。
因此,在同一个有效工作区里,后续运行另一个测试类,或者重新连接 MCP ,仍然可以复用已有编译状态,而不必把整个项目当成第一次见到。
这里复用的是编译结果,不是上一次“测试通过”的答案。测试仍然会在独立 JVM 中实际执行,代码变了,就检查新的执行结果。
这对 Agent 的开发过程有什么意义?

增量编译不是 AI 时代才需要的东西。恰恰相反,它是我们已经使用了很多年的开发能力。
只是 IDEA 和 Eclipse 把这部分做得太自然,我们习惯了改一点、跑一下,很少再去注意它在背后省了多少工作。
Agent 连续开发时,同样会经历这个过程:
调整一个条件→ 跑测试→ 发现边界不对→ 修改实现→ 再跑测试→ 补充一个场景→ 继续验证一次重复编译,只是一段等待;连续多轮,等待就会不断累积。
我希望 Agent 在每一轮里,把时间花在新的修改和验证上,而不是反复处理已经完成过的准备工作。
这也是 joLink 使用持久编译工作区的原因。
优雅:项目跑起来以后,还能继续管理它

除了速度,我还想改善另一个体验:启动应用不应该是一次性的命令,而应该是一段可以继续操作的开发过程。
这里换成 Spring Petclinic 演示应用启动和更新,固定提交为 818c4136ea971c21674525f9053de0d9c7ad8cfe。
这次应用监听本机 18093 端口,JDWP 端口为 15093。Agent 通过 java_application 发起启动,主要参数可以这样理解(项目路径为示意,省略本机环境配置):
{  "action": "launch",  "project_path": "/path/to/petclinic",  "main_class": "org.springframework.samples.petclinic.PetClinicApplication",  "ready_port": 18093,  "jdwp_port": 15093}joLink 负责相关构建准备和进程启动,之后 Agent 可以通过 java_status 查看状态、按需读取日志。需要调查运行行为时,再使用调试工具获取实际的调用栈和变量。
这轮应用启动后的 PID 是 52032。Agent 随后通过 java_status 查看状态,再实际请求兽医列表:/vets.html?page=0 返回 HTTP 500 ,暴露了非正数页码的处理问题。

更重要的是,修改代码以后,这个过程可以接着往下走。
对于已经由 joLink 管理的应用,Agent 可以调用:
{  "action": "restart"}joLink 会检测源码变化,进行增量编译,再应用新的编译结果。适合的修改优先使用 HotSwap ,不适合热替换的则重启 JVM ;需要重新执行应用初始化时,也可以明确选择重启。
这次修复只在 VetController 的分页入口增加了一行,把小于 1 的页码按第一页处理:
page = Math.max(1, page);Agent 应用补丁后,通过 joLink 的更新流程让改动生效,再重新请求相关接口。

这一次实际返回的更新方式是 HotSwap,只编译了 1 个源文件,替换的是 VetController。更新前后 PID 都是 52032,没有重新启动 JVM 。
更新指标实际结果更新方式 apply_methodhotswap编译类型 build_kindINCREMENTAL编译源文件数1编译耗时 compile_ms123.4 毫秒应用修改耗时 apply_ms89.6 毫秒更新操作总耗时 total_ms261.5 毫秒进程 PID52032 ,更新前后保持一致这个 261.5 毫秒是 joLink 更新操作本身的耗时,不包含模型编辑代码和后续 HTTP 检查。
更新后重新请求,结果也对应上了:
请求更新后的实际结果/vets.html?page=0HTTP 200 ,更新前为 500;返回第一页内容/vets.html?page=-1HTTP 200 ,返回与第一页一致的内容/vets.html?page=1HTTP 200 ,正常返回第一页的 5 位兽医/vets.html?page=2HTTP 200 ,仍然返回第二页的 1 位兽医/vets( JSON )HTTP 200 ,返回 6 位兽医,专长信息正常其中 page=0、page=-1 与 page=1 的完整 HTML 的 MD5 一致。

这次不是只收到一个“更新成功”,而是在原来的 JVM 中应用了修改,再通过新的请求看到了修复后的结果。
这样,Agent 操作的是同一个有状态的运行环境:
启动应用→ 请求接口→ 发现异常→ 读取日志或运行时变量→ 修改代码→ 应用修改→ 再次请求我想要的“优雅”,就是这些动作能够连起来。
编译失败了,拿到编译诊断;测试失败了,查看对应结果;应用还在启动,就继续等待;实际响应不符合预期,就沿着现有应用继续排查。
不用每一轮都重新组织一套运行过程,也不用为了知道当前发生了什么,把所有日志从头读一遍。
而且,跑单元测试与启动业务应用是两个独立入口。只需要验证某个测试类时,直接使用 Fast Test ,不必先把整个业务服务启动起来。
架构:规则、Skill 、MCP 和实际运行的部分

joLink 不只是几个工具名,它还提供配套的开发准则和 Skill 。
它们各自解决不同的问题。
全局规则负责表达工作原则。 比如“事上磨练”:先形成判断,通过实际执行取得证据;结果与判断不一致时,修正理解和实现,而不是不断给原来的猜测打补丁。核心是对改动的实际行为负责。
Skill 负责说明工具怎样使用。 例如,什么时候直接运行指定测试,怎样更新已经启动的应用,在哪里查看失败详情,以及如何继续一次尚未结束的操作。
MCP 是 Agent 调用这些能力的入口。 后面的 joLink Runtime 才实际维护编译工作区、执行测试、管理应用进程,并连接 JVM 调试能力。
可以简单理解成:
        agent 全局规则:怎样对待开发与验证 (大部分情况下会让 AI 更多的运行、测试项目,选择性安装)                 ↓                Skill:怎样使用这套工具                 ↓          Coding Agent                 ↓ MCP          joLink Runtime                 ↓    增量编译 / 测试 / 应用运行 / JVM 调试前面两部分帮助 Agent 组织工作,后面负责真正执行。joLink 的编译、测试、应用更新和调试机制,都由 joLink-Runtime 提供。
对 Agent 暴露的四个工具

工具主要做什么java_fast_test编译并运行指定的 JUnit / TestNG 测试,读取执行结果。java_application启动应用、应用代码修改,以及管理应用生命周期。java_status查看当前执行状态,按需读取构建和应用日志。java_debugger设置断点、观察异常、读取线程、调用栈和变量。这四个入口分别对应测试、应用操作、状态观察和运行时调查,Agent 根据任务选择需要的能力。
目前的情况

joLink 是 MIT 协议的开源项目,目前还在 Alpha 阶段。我自己在工作项目里持续使用,也在用不同的开源项目检查兼容性。
目前主要面向 Maven / Gradle Java 项目,支持指定测试、普通 Java / Spring Boot 应用运行,以及运行中的更新和调试。日常修改验证交给 joLink ,完整打包和 CI 仍然保留项目原有的构建流程。
接下来想找几位平时用 AI 写 Java 的开发者,拿自己的项目试一试。安装是否顺利、项目能不能跑、连续修改时是否省事,这些实际反馈对我很重要。
项目和安装说明:
https://github.com/L1ch404/jolink-runtime
再叠个甲,并不是说只有用了 joLink 才能让 AI 去启动、测试 Java 项目,只是 joLink 可以让这件事情变得更优雅、快捷
我们给自己配了用了很多年的 Java 开发环境,我也想给 Agent 配一套。让它改完以后,能顺手跑起来、看到结果,再接着改。


⚠️内容来自互联网,如有侵权请点击反馈!侵权投诉
本帖共 1 条回复,登录后即可查看

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

hot.热文换一批
  1. 宇宙到底是大还是小?一张纸对折103次的厚度,宇宙已装不下
  2. 别眨眼!人类首次"看见"光子!你家灯泡里全是它!
  3. 人类至今无法彻底解释的15个顶级现象,看完敬畏万物
  4. 二十出头就显成熟?揭秘上一代人的"大人模样"背后原因
  5. 明明含有氢和氧,氢可燃氧助燃,为什么水偏偏不能燃烧?
  6. 🎉庆祝应用中心上架15个插件了,抽波优惠券![开奖时间:2026-04-26 20:00]
  7. 人类已发现外星生命?科学家:就在12亿公里外,可能以甲烷为食
  8. 又一个新游戏上线了,欢迎体验!
  9. 自来水微塑料3000万/升,煮沸后降到480万,比桶装水高还是低?
  10. 女装退货率飙至80%,商家为何挂密码锁发货?
  11. 现在这金价是不是还有余地
  12. 古人为何50岁就百病缠身?揭秘1972年7月30日“马王堆女尸”出土之谜
  13. 世界上最凶猛的10种鸟,金雕到底有多厉害?猎杀野狼轻而易举?
  14. 中国真挖到“宝”了!海水里藏45亿吨铀,美国70年难题被突破
  15. 太阳和银河系之间,还有一个神秘结构?
  16. 科学家:在人类出生前,有两种神秘的力量帮助构建了人脑
  17. 下潜到1万多米的海底,人类发现了不该出现的东西?需要引起警惕
  18. 古人到底能有多苦?这么说吧,现代人在古人面前不值一提
  19. 🌱牛马论坛-每日早报-2026年10月08日
  20. 终于装上了LightSNS,然后模块一通买,还是花了上千
  21. 吃一块能顶一天?军用压缩饼干为啥抗饿?
  22. 小时候父母不让玩手机的秘密,网友亲测:经历过才懂!
  23. 牛马论坛[NIUMABBS]-行为规范准则
  24. 测试
牛马论坛(niumabbs.com),一个专注于分享日常新鲜事、职场工作点滴、摸鱼乐趣与各类生活感悟的交流平台。

    关注我们

  • 加入Q群
  • 微信客服
  • QQ客服
Copyright © 2026 NIUMABBS 版权所有 All Rights Reserved. |网站地图 劰载中...
关灯 在本版发帖
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表