Java类卸载之后无法删除源文件,PF4J

背景

我们有一个Plugin的管理系统,可以实现Jar包的热装载,内部是基于一个Plugin管理类库 PF4J,类似于OSGI,现在是GitHub上一个千星项目。
以下是该类库的官网介绍

A plugin is a way for a third party to extend the functionality of an application. A plugin implements extension points declared by application or other plugins. Also a plugin can define extension points. With PF4J you can easily transform a monolithic java application in a modular application.

大致意思就是,PF4J可以动态地加载Class文件。同时,它还可以实现动态地卸载Class文件。

问题描述

有个新需求,热更新Plugin的版本。也就是说,将已经被load进JVM的旧Plugin版本ubload掉,然后load新版本的Plugin。PF4J工作得很好。为了防止过期的Plugin太多,每次更新都会删除旧版本。然而,奇怪的事发生了:

  • 调用File.delete()方法返回true,但是旧文件却还在
  • 手动去删除文件,报进程占用的错误
  • 当程序结束JVM退出之后,文件就跟着没了

以下是简单的测试代码,目前基于PF4j版本3.0.1

public static void main(String[] args) throws InterruptedException {
   
    // create the plugin manager
    PluginManager pluginManager = new DefaultPluginManager();
    // start and load all plugins of application
    Path path = Paths.get("test.jar");
    pluginManager.loadPlugin(path);
    pluginManager.startPlugins();

    // do something with the plugin

    // stop and unload all plugins
    pluginManager.stopPlugins();
    pluginManager.unloadPlugin("test-plugin-id");
    try {
   
        // 这里并没有报错
        Files.delete(path);
    } catch (IOException e) {
   
        e.printStackTrace();
    }

    // 文件一直存在,直到5s钟程序退出之后,文件自动被删除
    Thread.sleep(5000);
}

去google了一圈,没什么收获,反而在PF4J工程的Issues里面,有人报过相同的Bug,但是后面不了了之被Close了。

问题定位

看来只能自己解决了。
从上面的代码可以看出,PF4J的Plugin管理是通过PluginManager这个类来操作的。该类定义了一系列的操作:getPlugin(), loadPlugin(), stopPlugin(), unloadPlugin()

unloadPlugin

核心代码如下:

private boolean unloadPlugin(String pluginId) {
   
    try {
   
        // 将Plugin置为Stop状态
        PluginState pluginState = this.stopPlugin(pluginId, false);
        if (PluginState.STARTED == pluginState) {
   
            return false;
        } else {
   
            // 得到Plugin的包装类(代理类),可以认为这就是Plugin类
            PluginWrapper pluginWrapper = this.getPlugin(pluginId);
            // 删除PluginManager中对该Plugin各种引用,方便GC
            this.plugins.remove(pluginId);
            this.getResolvedPlugins().remove(pluginWrapper);
            // 触发unload的事件
            this.firePluginStateEvent(
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值