java新版本-java25学习笔记(二)运行时基线先统一

发表于 2026-01-13 22:18 1808 字 10 min read

Spring AI学习笔记(四)工具调用和MCPSpring AI学习笔记(三)RAG从文档入库到回答Spring AI学习笔记(二)ChatClient从怎么调到怎么封装Spring AI学习笔记(一)它到底解决什么问题java新版本-java25学习笔记(四)用JFR和GC日志做一次体检java新版本-java25学习笔记(三)虚拟线程要和资源边界一起看java新版本-java25学习笔记(二)运行时基线先统一java新版本-java25学习笔记(一)LTS版本对比和学习路线主流AI Agent能力对比与工程选型我用Kiro做了个自己的工具站盘一盘虚拟线程我用Trae做了个AstrBot的AI角色扮演插件Python初学笔记(六)常用标准库先学这几个Python初学笔记(五)读写文件和处理异常Python初学笔记(四)函数让代码开始有结构Python初学笔记(三)条件、循环和推导式Python初学笔记(二)变量和基础类型比想象中重要Python初学笔记(一)先把环境和运行方式弄明白主流AI大模型能力对比Java 21和Spring Boot 3升级笔记(五)日志指标与可观测性Java 21和Spring Boot 3升级笔记(四)数据访问层适配Java 21和Spring Boot 3升级笔记(三)虚拟线程使用边界Java 21和Spring Boot 3升级笔记(二)Jakarta迁移要点Java 21和Spring Boot 3升级笔记(一)工程基线整理How Can We Tolerate Magic Values! Major Overhaul of JPA Specification!处理生僻字乱码:JPA框架对于Oracle的NVarchar2,NChar,NClob类型支持Redis Stream能不能当轻量消息队列用RocketMQ 5学习笔记:普通消息之外要看什么事件流不是换个消息队列这么简单Kubernetes学习笔记04:发布、排障和观测Kubernetes学习笔记03:配置、密钥和存储Kubernetes学习笔记02:Deployment、Service和IngressKubernetes学习笔记01:Pod和控制器mysql索引原理02--存储引擎索引的实现mysql索引原理01--索引的数据结构
This post is not yet available in English. Showing the original.
  这篇继续记录。第一篇看了几个 LTS 版本的差异和 Java 25 的新特性,这一篇回到后端项目本身:学习新版本时,先把运行时基线统一起来。   Java 25 已经不只是发布新闻了。对很多 Java 后端团队来说,它开始进入“能不能系统学习和评估”的阶段。   我觉得 LTS...

前言

  这篇继续记录java新版本-java25学习笔记。第一篇看了几个 LTS 版本的差异和 Java 25 的新特性,这一篇回到后端项目本身:学习新版本时,先把运行时基线统一起来。

  Java 25 已经不只是发布新闻了。对很多 Java 后端团队来说,它开始进入“能不能系统学习和评估”的阶段。

  我觉得 LTS 版本的落地,第一步不是去追某个新语法,也不是马上在生产里切换镜像。更重要的是统一运行时基线。

  所谓运行时基线,就是项目到底用什么 JDK 编译、用什么 JDK 测试、用什么 JDK 运行、容器镜像从哪里来、JVM 参数怎么配、观测探针是否兼容。这些东西如果不统一,后面问题会很难排查。

先盘点现状

  升级或评估 Java 25 前,先不要急着改 POM。

我会先列一张表,把所有服务当前情况写清楚:

1.服务名。 2.当前 JDK 版本。 3.Spring Boot 或框架版本。 4.构建工具版本。 5.运行镜像。 6.是否使用 Java Agent。 7.核心依赖。 8.最近一次完整回归时间。

这张表看起来像项目管理工作,但很有用。很多团队以为自己已经统一 Java 21,实际一查发现有的服务还在 17,有的 CI 用 21,本地有人用 23,生产镜像又是另一套。

这种情况下直接评估 Java 25,结果会很乱。

和几个 LTS 版本的升级距离

  不同 LTS 版本升级到 Java 25,难度完全不一样。

当前版本到 Java 25 的主要问题
Java 8跨度最大,依赖、框架、反射、JVM 参数、构建插件都要系统检查
Java 11比 Java 8 好一些,但很多老框架和内部 API 访问仍然要清理
Java 17已经接近现代 Java 基线,重点看 Spring Boot 3、Agent、容器镜像和测试插件
Java 21距离最近,适合重点评估 Java 25 新特性、JFR、AOT、GC 和启动表现

  所以“升级 Java 25”不是一个统一动作。Java 8 项目更像迁移工程,Java 21 项目更像新 LTS 验证。

编译和运行要一致

  Java 项目里经常会出现“编译 JDK”和“运行 JDK”不一致。

比如 CI 用 JDK 25 编译,运行镜像却还是 JDK 21。短期可能因为 target 设置较低而能跑,但这会让问题变得不清楚。

我更喜欢明确指定编译 release:

<properties>
    <maven.compiler.release>25</maven.compiler.release>
</properties>

如果只是评估阶段,也可以先保持 release 21,用 JDK 25 跑测试,观察运行兼容性。但无论哪种方式,都要写清楚目标。

不要让构建脚本、IDE、CI、Dockerfile 各自猜版本。

Maven 和插件也要看

  JDK 升级时,Maven 本身和插件版本也要检查。

常见要看的插件包括:

1.maven-compiler-plugin。 2.maven-surefire-plugin。 3.maven-failsafe-plugin。 4.jacoco-maven-plugin。 5.spring-boot-maven-plugin。 6.代码生成插件。

测试插件尤其重要。很多时候编译能过,单元测试启动时出问题,原因就是测试运行器或字节码增强工具版本太旧。

如果项目里有 Lombok、MapStruct、QueryDSL、字节码增强、覆盖率统计,这些都要一起验证。

Docker 镜像不要随便换

  容器时代,JDK 升级一定绕不开基础镜像。

镜像不仅包含 JDK,还包含系统库、证书、时区、字体、用户、启动脚本。不要只看 tag 里写了 25 就直接替换。

我会先做一个最小验证:

1.应用能启动。 2.HTTPS 访问正常。 3.时区正确。 4.日志时间正确。 5.字体或报表功能正常。 6.健康检查正常。 7.容器内存识别正常。

特别是生成 PDF、验证码、图片处理的服务,基础镜像过于精简时可能会缺字体或系统依赖。

JVM 参数要清理

  很多服务的 JVM 参数是从很久以前复制来的。

比如一堆 GC 参数、元空间参数、日志参数、容器参数混在一起。升级到 Java 25 时,这些参数应该重新审视。

我会把参数分成三类:

1.必须保留:内存上限、必要的系统属性。 2.需要验证:GC 选择、日志、诊断参数。 3.应该删除:过时参数、没人知道作用的参数。

不要把老版本调优经验机械搬到新 JDK。尤其是 GC 默认行为、容器感知、日志格式,这些年都变化过。

更稳的做法是先用简洁参数跑压测,再根据数据调整。

Agent 兼容性别忘了

  很多 Java 服务都会挂 Agent。

比如 APM、OpenTelemetry Java Agent、SkyWalking、Arthas、字节码安全扫描、性能分析工具。这些 Agent 深度接触字节码和 JVM 行为,JDK 升级时一定要验证。

如果 Agent 不兼容,可能表现为启动失败、类增强失败、性能异常、链路缺失。

所以 Java 25 评估环境里,要尽量模拟生产启动方式。不要只用裸 jar 跑通,就以为生产也能跑。

启动命令、Agent 参数、环境变量、容器资源限制都要一致。

测试分层推进

  运行时基线统一后,可以开始测试。

我会按层推进:

1.编译测试。 2.单元测试。 3.集成测试。 4.应用启动测试。 5.核心接口回归。 6.压测。 7.灰度。

其中集成测试很关键。很多兼容问题只会在真实数据库、Redis、消息队列、HTTP Client 上暴露。

如果项目已经有 Testcontainers,这一步会轻松很多。没有的话,至少要在测试环境跑核心流程。

不要一次升级所有服务

  多服务系统里,不建议所有服务同时切 Java 25。

先选一个边界清楚、流量可控、依赖不复杂的服务做试点。试点稳定后,再扩大范围。

试点服务要观察:

1.启动时间。 2.内存曲线。 3.GC 行为。 4.P95/P99 延迟。 5.错误率。 6.日志和链路是否正常。 7.回滚是否顺畅。

升级运行时不是单点代码改动,它会影响整个服务生命周期。

一个 Java 25 基线小练习

  学习 Java 25 时,可以先写一个小文件,把当前 JDK、运行时和系统属性打印出来。

新建runtime-baseline.java

void main() {
    System.out.println("java.version = " + System.getProperty("java.version"));
    System.out.println("java.vendor = " + System.getProperty("java.vendor"));
    System.out.println("java.vm.name = " + System.getProperty("java.vm.name"));
    System.out.println("os.name = " + System.getProperty("os.name"));
    System.out.println("availableProcessors = " + Runtime.getRuntime().availableProcessors());

    long maxMemoryMb = Runtime.getRuntime().maxMemory() / 1024 / 1024;
    System.out.println("maxMemoryMB = " + maxMemoryMb);
}

运行:

java runtime-baseline.java

  再分别在本地、CI、Docker 镜像里跑一次。如果输出不一致,就说明运行时基线还没有统一。

小结

  Java 25 学习和评估的第一步,是统一运行时基线。

  JDK、Maven、插件、Docker 镜像、JVM 参数、Agent、CI、测试环境、生产环境,都要在同一张图里看。

  只有基线清楚,后面讨论虚拟线程、GC、性能、语言特性才有意义。不然任何问题都可能变成“到底是哪套运行时导致的”。

If you enjoyed this, leave a comment~

© 2019 - 2026 VincentHo @VincentHo
Powered by theme astro-koharu · Inspired by Shoka