ENTRYPOINT 少写一对中括号,Spring Boot 的优雅停机就白开了
Dockerfile 用 shell 形式的 ENTRYPOINT 时,docker stop 的 SIGTERM 到不了 Java 进程,10 秒后直接被 SIGKILL;写对了也要让 Docker 的宽限期长过 Spring Boot 的 30 秒停机超时。用 Spring Boot 4.1.1 实测四种情况。
围绕 spring-boot 的技术文章与经验分享。
共 91 篇文章Dockerfile 用 shell 形式的 ENTRYPOINT 时,docker stop 的 SIGTERM 到不了 Java 进程,10 秒后直接被 SIGKILL;写对了也要让 Docker 的宽限期长过 Spring Boot 的 30 秒停机超时。用 Spring Boot 4.1.1 实测四种情况。
Spring Boot 4.1.1 加 spring-boot-starter-batch-data-mongodb,Spring Batch 6.0.5 的 JobRepository 自动落到 MongoDB:条件报告、第 57 条失败后重启只读剩余 50 条、元数据文档结构,以及单机 Mongo 事务报错、序列未初始化、无索引、无集合前缀等坑。
堆固定 256M 的 Spring Boot 应用,RSS 从 268M 涨到 552M,MemoryMXBean 的 non-heap 只多了 1M。在 JDK 27 上用 NMT 的 baseline 和 summary.diff 实测,直接内存记在 Other 下面,线程栈 reserved 和 committed 差了几十倍,还顺手撞上了 MaxDirectMemorySize 默认等于 -Xmx 的 OOM。
MCP Java SDK 2.1.0 新增 addToolFilter 按请求过滤 tools/list,Streamable HTTP 服务端默认开启 30 分钟保活和空闲会话清理,并移除 2024-11-05 协议。在 Spring Boot 4.0.5 中实测:隐藏的工具按名字仍可调用;默认会话清理留下一个非守护线程,关闭上下文后靠 main 返回退出的进程不会结束,SIGTERM 停机不受影响。
用官方 tar 包起 Pulsar 5.0.0 standalone,Spring Boot 4.1.1 默认带的 4.2.4 客户端直接能收发。换成 5.0 客户端时只改版本号会先后撞上 slog 和 shade 两个报错,改用 pulsar-client-v5-all,再排除 pulsar-client-all 和 log4j-to-slf4j 两个包后跑通。
Spring Boot 4.1.1 的 spring-boot-starter-opentelemetry 实测:不用 agent 把 trace、指标和日志推到本地 OTel Collector。默认 10% 采样、trace 地址没有默认值、老属性名被忽略、Logback appender 的 incubator 版本冲突等坑,以及和 Java agent 的取舍。
Spring Boot 4.1.1 + Spring Data JPA 4.1.1 实测 AOT 仓库:生成的 Impl__AotRepository 有 8 个方法,动态投影和 ScrollPosition 回退运行时;9 次启动中位数,AOT 模式下关掉仓库生成 3.191 秒,打开后 2.659 秒,普通 JVM 3.309 秒。
Boot 3 时代的 Jackson 2 代码在 Spring Boot 4.1.1 下实测迁移:包名换成 tools.jackson、ValueSerializer、JsonMapperBuilderCustomizer、rebuild()、JacksonException,spring.jackson 旧配置一个启动失败一个静默失效,以及用 spring-boot-jackson2 暂留 Jackson 2。
512M 的容器里不配 JVM 参数,Spring Boot 的最大堆只有 128M;把 -Xmx 设得比容器上限大,进程会被直接 OOMKilled。用 Spring Boot 4.1.1 和 JDK 21 在 Docker 里把三种情况实测了一遍。
同一个 Spring Boot 4.1.1 项目在 JDK 21 与 JDK 25 上实测:JEP 491 之后 synchronized 不再钉住载体线程,ThreadLocal 当缓存在虚拟线程下失效,ScopedValue 不会自动穿过普通执行器,连接池成为新的瓶颈。