You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级JDK8至JDK11后,sun.misc.URLClassPath替代类咨询

JDK 11中替代sun.misc.URLClassPath实现运行时Jar卸载的方案

问题描述

我有一个基于JDK 8实现的运行时卸载.jar文件的方法,升级到JDK 11后,程序无法识别sun.misc.URLClassPath类。请问JDK 11中有哪个类可以替代它?

原JDK 8实现代码:

import sun.misc.URLClassPath;
    
public static boolean unloadJar(String jarFile, ClassLoader classLoader) {
        try {
            if (classLoader instanceof URLClassLoader) {
                URLClassPath ucp = (URLClassPath)getField(classLoader, "ucp", URLClassLoader.class);
                ArrayList<URL> path = (ArrayList<URL>)getField(ucp, "path");
                ArrayList<?> loaders = (ArrayList<?>)getField(ucp, "loaders");
                boolean isRemovedFromPath = path.removeIf(p -> p.getFile().endsWith(jarFile));
                boolean isRemovedFromLoaders = loaders.removeIf(l -> {
                    try {
                        URL csu = (URL)getField(l, "csu");
                        return csu.getFile().endsWith(jarFile);
                    } catch (NoSuchFieldException | IllegalAccessException e) {
                        return false;
                    }
                });
    
                return isRemovedFromPath && isRemovedFromLoaders;
            } else {
                String msg = String.format("Class loader type is mismatched. Required: %s, actual: %s",
                        classLoader.getClass().getName(), URLClassLoader.class.getName());
                logger.debug(msg);
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

解决方案

sun.misc.URLClassPath是JDK内部非公开API,从JDK 9开始被模块化系统隐藏,JDK 11中已完全移除,没有直接对应的替代类。Java官方从设计上不推荐依赖内部API实现Jar卸载,更规范的做法是通过自定义类加载器实现动态Jar加载与卸载:

核心原理

Java中类的生命周期与加载它的类加载器绑定,当自定义类加载器被GC回收(且无任何该类加载器加载的类实例、静态引用存在),其加载的所有类也会被自动卸载。

实现示例

  1. 自定义URL类加载器
import java.net.URL;
import java.net.URLClassLoader;

public class JarClassLoader extends URLClassLoader {
    public JarClassLoader(URL[] urls, ClassLoader parent) {
        // 传入父类加载器遵循双亲委派模型
        super(urls, parent);
    }

    // 动态添加Jar的方法
    public void addJar(URL jarUrl) {
        super.addURL(jarUrl);
    }
}
  1. 加载与卸载Jar的使用方式
import java.net.MalformedURLException;
import java.net.URL;

public class JarUnloadDemo {
    public static void main(String[] args) throws Exception {
        // 1. 加载目标Jar
        URL jarUrl = new URL("file:/path/to/your/target.jar");
        JarClassLoader jarLoader = new JarClassLoader(new URL[]{jarUrl}, Thread.currentThread().getContextClassLoader());
        
        // 2. 使用类加载器加载并调用类(示例)
        Class<?> demoClass = jarLoader.loadClass("com.example.DemoClass");
        Object instance = demoClass.getDeclaredConstructor().newInstance();
        demoClass.getMethod("demoMethod").invoke(instance);

        // 3. 执行卸载操作
        // 释放所有对类实例的引用
        instance = null;
        // 释放对类加载器的引用
        jarLoader = null;
        // 提示:实际业务中无需手动调用GC,JVM会自动在合适时机回收
        System.gc();
    }
}

注意事项

  • 避免使用系统类加载器或应用类加载器加载需要卸载的Jar,因为这些类加载器通常会被JVM长期持有,无法被GC回收。
  • 确保所有通过自定义类加载器加载的类实例、静态变量等引用都被清空,否则类加载器无法被回收,Jar也无法卸载。
  • 原代码中通过反射修改内部类字段的方式在JDK 11及以后完全不可行,模块化系统会阻止对内部API的反射访问,即使开启相关权限也不推荐(后续版本可能彻底禁用)。

内容的提问来源于stack exchange,提问作者NoName

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 14:25:17