ServiceLoader.reload 不会清除静态变量或单例缓存,仅重新扫描 META-INF/services/xxx 并替换迭代器缓存,类仍由原 ClassLoader 持有,静态字段和已有实例状态保持不变。

ServiceLoader.reload 并不会清除已加载实现类的静态变量或单例缓存。
ServiceLoader.reload 的实际行为
Java 的 ServiceLoader.reload() 只是重新扫描并加载 META-INF/services/xxx 文件中声明的服务提供者类,创建新的实例,并替换内部的迭代器缓存(即下次调用 iterator() 时返回新加载的实例)。它不触发类卸载,也不影响已加载类的静态字段、静态初始化块、或任何已有实例的状态。
这意味着:
- 之前通过
ServiceLoader.load()创建的实现类实例仍存在于堆中(除非被 GC 回收); - 实现类中的
static变量(如缓存 Map、计数器、连接池等)不会被重置; - 类本身仍由原 ClassLoader 持有,
reload()不会重新定义或卸载该类。
为什么静态变量不会被“清除”
Java 类型系统中,类的静态成员生命周期绑定于其 Class 对象,而 Class 对象的生命周期由 ClassLoader 管理。默认情况下,ServiceLoader 使用线程上下文类加载器(或显式传入的类加载器),reload() 不会更换或重启该类加载器,因此原有类定义和其静态状态保持不变。
例如:若某服务实现类中有如下代码:
public class MyService implements Service {
private static final Map<String, Object> CACHE = new ConcurrentHashMap<>();
static { System.out.println("Loaded!"); }
}
多次调用 reload() 后,CACHE 依然存在且内容未清空,“Loaded!” 也不会再次打印。
如需真正“重置”实现类状态,可考虑以下方式
-
手动清理:在服务实现类中提供
reset()或clearCache()方法,并在 reload 前主动调用; - 使用独立 ClassLoader:每次 reload 时换用新的自定义 ClassLoader 加载服务类(较重,需注意内存泄漏与类型隔离);
-
避免静态状态:将缓存等状态外移到服务实例内部(非 static),确保每次
iterator().next()得到的是干净新实例; -
结合依赖注入容器:如 Spring,用
@RefreshScope或动态注册 Bean 替代原生 ServiceLoader,便于控制生命周期。
小结
ServiceLoader.reload() 是轻量级的服务发现刷新机制,不是类热更新或状态重置工具。它不碰静态变量、不卸载类、不清理已有实例。需要状态隔离或重置,必须由业务代码显式处理,不能依赖 reload 自动完成。

















