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