Spring Boot DevTools

背景 开发 Spring Boot 时,spring-boot-devtools 提供 快速重启 与 静态资源热刷新,常被误认为「和 IDE HotSwap 一样改 Java 就能生效」。本文说明它实际做什么,并与 开发期热替换、JPDA 区分。 Spring Boot 总览见 Spring Boot。 依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> 仅在开发 classpath 使用;生产打包应排除(optional + 不打进 fat jar 的常见做法)。 两个 ClassLoader(Restart) DevTools 默认启用 Restart: ClassLoader 加载内容 变更时 base 第三方依赖(spring-boot-starter-* 等) 一般不 reload restart 你的 target/classes 业务代码 监控到变更后 快速重启 应用上下文 「快速重启」不是 HotSpot 的 类热替换:而是 停掉当前 Spring 上下文再拉起,但 base ClassLoader 保留,比冷启动整个 JVM 快。 因此: 改 业务 Java 类 → 触发 restart(仍是一次上下文重建,不是 JPDA 改方法体) 改 静态资源(src/main/resources 下 html/css 等)→ LiveReload 通知浏览器刷新,无需重启 JVM 与 HotSwap / BTrace 的对比 机制 层级 典型场景 DevTools Restart Spring 上下文 + 双 ClassLoader 本地改代码后几秒内重新跑 Bean IDE HotSwap JVM + JPDA / 有限 redefine Debug 下改 方法体 DCEVM + HotSwapAgent 增强 HotSpot + javaagent 开发机放宽 redefine、重载 Spring 配置 BTrace attach Attach + ASM 已运行 进程观测,非开发热更 DevTools 不 使用 Attach API 给业务类插探针;也 不 替代 mvn spring-boot:run 外的生产部署。 ...

Created 31316-05-31 · Updated 31316-05-31 · 1 min · 189 words · -

JVMTI(Java 虚拟机工具接口)

背景 调试器断点、IDE 热替换、jcmd 部分能力、Attach API 的 loadAgentLibrary、native agent,底层都依赖 JVM 提供的 native 级 工具接口。在 HotSpot/OpenJDK 上,这一层主要是 JVMTI。 JVMTI 是什么 JVMTI(Java Virtual Machine Tool Interface)是 JVM 实现的 C 语言 native 接口(jvmti.h),用于: 调试:断点、单步、查看栈与局部变量 分析:采样、分配追踪 类与字节码:监听类加载、重定义已加载类(与 IDE HotSwap 相关) Agent:native agent 在 Agent_OnLoad 里通过 JavaVM::GetEnv 拿到 jvmtiEnv 它 不是 Java 应用直接 import 的包;Java 侧看到的是更高层的封装。 前身(已淘汰) 用途 JVMDI 调试 JVMPI 性能分析 JDK 5+ 由 JVMTI 统一替代(见 JPDA 文中的历史说明)。 与 JPDA、Instrumentation 的关系 IDE / jdb(调试器) ↓ JDI(Java API) ↓ JDWP(线协议,如 dt_socket) ↓ JVMTI Agent(如 jdwp.so)→ JVMTI 调用 ↓ HotSpot JVM java.lang.instrument(Java Agent,premain/agentmain) ↓ JVM 内部同样依赖 JVMTI 等 native 能力实现 redefine/retransform 接口 语言 典型用途 JVMTI C / native 调试器后端、profiler、native agent JPDA(JDI + JDWP + JVMTI) 调试体系 Eclipse/IDEA 远程调试、JDB java.lang.instrument Java BTrace、Arthas、-javaagent、部分 APM 三者都落在 同一 JVM 进程 里,但入口不同:写 Java 诊断 agent 用 instrument + Attach;写调试器走 JPDA;写 native 库 agent 用 JVMTI + loadAgentLibrary。 ...

Created 31316-05-31 · Updated 31316-05-31 · 1 min · 195 words · -

jcmd

背景 本文记录 JDK 8 生产环境下的用法:在主机上查看正在运行的 Java 进程 PID,并向目标 JVM 发送诊断命令(线程栈、堆 dump、JVM 参数等)。常与 BTrace attach 前配合使用(jcmd -l 列进程)。 New Features in JDK7 update 4 JRockit command line utility JRCMD (JRockit Command). JRCMD was a command line tool to enumerate the Java processes running on the local machine, and to send commands (referred to as “Diagnostic Commands”) to them. JRCMD has been renamed JCMD (Java Command). jcmd 用于向正在运行的 JVM 发送诊断信息请求,从 JDK 1.7 开始提供,可以说是 jstack 和 jps 的结合体。 ...

Created 6066-02-06 · Updated 30306-05-30 · 3 min · 589 words · -

Java 生产环境诊断工具选型

背景 生产环境曾运行在 JDK 8。线上出现问题时,用 BTrace attach 到运行中的 JVM:按条件过滤慢方法(例如耗时超过 9ms),持续输出,不改代码、不重启。 当时 JFR 仍是商业特性,attach 式动态追踪是可行且低成本的方案之一。本文先记录 JDK 8 时代的诉求与 BTrace 用法,其它 JDK 版本下的工具对照见文末章节。 JDK 8 时代 BTrace 在解决什么 从 BTrace 使用笔记 中的脚本可以看出,核心需求是: attach 到运行中的 JVM,不重启 按条件过滤慢方法(例如大于 9ms) 持续输出,而不是只看一次快照 必要时查看参数、返回值、调用栈 示例脚本(慢调用过滤 + 计数): @OnMethod(clazz = "com.wiloon.package0.Class0", method = "method0", location = @Location(Kind.RETURN)) public static void printMethodRunTime(@ProbeClassName String probeClassName, @Duration long duration) { long d = duration / 1000000; if (d > 9) { i++; println("index: " + i + ", timestamp:" + timestamp("HH:mm:ss") + ", " + probeClassName + ", duration: " + d + " ms"); } } 执行方式: ...

Created 30306-05-30 · Updated 30306-05-30 · 2 min · 415 words · -

spring basic

spring basic @RestController @RestController 是 @Controller 与 @ResponseBody 的组合注解,用于编写 RESTful API:控制器方法的返回值会直接写入 HTTP 响应体(通常是 JSON),而不是交给视图解析器去渲染页面。 @RestController @RequestMapping("/api/comments") public class CommentController { @GetMapping("/{id}") public Comment get(@PathVariable long id) { return commentService.findById(id); } } 上例中,Comment 对象会被 HttpMessageConverter(如 Jackson)序列化为 JSON 返回给客户端。 适用场景: 前后端分离:Vue、React、移动端等通过 HTTP 调用后端接口 微服务之间的 HTTP 调用 任何「请求数据 → 返回 JSON/XML」的 API 不适用场景: 传统的服务端渲染 Web 应用(JSP、Thymeleaf 等):这类应用需要 @Controller 返回视图名或 ModelAndView,由视图解析器渲染 HTML 页面 @Controller public class PageController { @GetMapping("/home") public String home(Model model) { model.addAttribute("title", "Home"); return "home"; // 解析为 home.jsp 或 templates/home.html } } 若把 JSP/Thymeleaf 页面控制器写成 @RestController,返回值会被当作响应体内容(例如字符串 "home" 会原样输出),而不会走视图解析,页面无法正常渲染。 ...

Created 5056-01-05 · Updated 20206-05-20 · 2 min · 352 words · -

TypeScript

JavaScript vs TypeScript 对比 同样的用户问候功能,JS 和 TS 写法对比: // JavaScript 版本 function greetUser(user) { return "Hello, " + user.name + "! You are " + user.age + " years old."; } const user = { name: "Alice", age: 25 }; console.log(greetUser(user)); // Hello, Alice! You are 25 years old. console.log(greetUser({ name: 42 })); // 不报错,但输出结果异常:Hello, 42! You are undefined years old. // TypeScript 版本 interface User { name: string; age: number; } function greetUser(user: User): string { return `Hello, ${user.name}! You are ${user.age} years old.`; } const user: User = { name: "Alice", age: 25 }; console.log(greetUser(user)); // Hello, Alice! You are 25 years old. console.log(greetUser({ name: 42 })); // ❌ 编译错误:name 应为 string,不能传 number TypeScript 在编写代码时就能发现类型错误,而不是等到运行时出现奇怪的 bug。 ...

Created 13136-06-13 · Updated 17176-05-17 · 3 min · 430 words · -

JDK 17 升级到 JDK 21 的变更汇总

JDK 17 到 JDK 21 跨越了 JDK 18、19、20 三个非 LTS 版本。本文汇总这四个版本引入的重要变更,重点关注 breaking change 和需要主动迁移的部分。 JDK 18(2022 年 3 月) Breaking Change UTF-8 成为默认字符集(JEP 400) 这是 17 → 21 迁移中最常见的隐性 breaking change。JDK 18 起,Charset.defaultCharset() 固定返回 UTF-8,不再跟随操作系统区域设置。 受影响的场景: new String(bytes) — 未指定编码,依赖平台默认值 new FileReader(file) — 未指定编码 System.out.println() 输出非 ASCII 字符 读写文件时未显式指定编码 对 Linux 生产环境的实际影响 大多数现代 Linux 发行版默认 locale 是 en_US.UTF-8 或 zh_CN.UTF-8,JDK 17 在这类环境下默认字符集本来就是 UTF-8,因此 JDK 18 的这一变更对标准 Linux 服务器基本无感。 真正有风险的场景: Windows 开发/测试环境 — Windows 默认编码是 GBK/CP936,本地测试通过但部署到 Linux 后行为不同 精简容器镜像 — 某些极简 Docker 镜像不设置 locale,LANG 为空,JDK 17 此时默认字符集可能是 US-ASCII,升级到 JDK 18 后反而统一成了 UTF-8 遗留系统 — 有意依赖 GBK 平台编码处理中文数据(如读老数据库导出文件)的项目会出问题 修复方式:所有涉及字节/字符转换的地方显式指定 StandardCharsets.UTF_8。 ...

Created 13136-05-13 · Updated 13136-05-13 · 3 min · 625 words · -