核心思路是用新类加载器加载更新后的类,通过接口解耦与volatile引用替换实现无感切换:一、面向接口编程,如iorderprocessor;二、自定义classloader打破双亲委派,每次new新实例加载class;三、volatile静态引用+原子赋值确保线程安全切换;四、配合文件监听与自动编译形成开发闭环。

核心思路是:用新类加载器加载更新后的类,再通过接口解耦+引用替换,让业务对象“悄然切换”,不中断调用链。
一、必须面向接口编程
热加载无法直接替换已加载的类实例,但可以替换实现该接口的新实例。所以所有可热更的业务逻辑,必须定义明确接口。
- 例如定义 IOrderProcessor 接口,声明
process(Order order)方法 - 真实逻辑写在
OrderProcessorV1、OrderProcessorV2等具体类中,且都实现该接口 - 外部代码只持有
IOrderProcessor类型的引用,不依赖具体类名或包路径
二、自定义类加载器并打破双亲委派
每次热更时,必须使用**全新实例**的类加载器加载新 class 文件,否则 JVM 会认为是重复加载而忽略。
- 继承
ClassLoader,重写findClass(String name),从指定目录(如./hotfix/)读取 .class 字节码 - 关键:不要调用
super.loadClass(),避免触发双亲委派;也不重写loadClass除非需完全接管 - 确保每次热更都 new 一个该类加载器实例,旧加载器不再创建新类,且无强引用残留
三、安全替换运行中的对象引用
不能直接修改 final 或 static 引用,要用线程安全、原子性可控的方式切换。
- 将业务对象声明为
volatile static IOrderProcessor currentProcessor - 提供
reload()方法:读取新 class 文件 → 用新加载器加载 → 实例化新对象 → 原子赋值给currentProcessor - 业务调用方始终通过
currentProcessor.process(...)调用,无需感知版本变化 - 旧对象若持有状态(如缓存、连接),应在 reload 前主动 close 或 reset,避免资源泄漏
四、配合文件监听与自动编译(开发态实用链路)
真正落地时,热加载不是手动拷 class 文件,而是形成“改源码 → 自动编译 → 触发 reload”的闭环。
- 用
java.nio.file.WatchService监听src/main/java/**/IOrderProcessor.java变更 - 变更后调用
javax.tools.JavaCompiler编译为target/classes/com/example/OrderProcessor.class - 将编译结果复制到热加载目录(如
hotlib/OrderProcessor.class),再触发 reload 流程 - 建议加简单校验:比对 class 文件最后修改时间或 CRC32,避免重复加载相同版本
不复杂但容易忽略










