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

ClassLoader加载类成功但实例化时因依赖类缺失报错

类加载异常分析与解决

问题本质

你碰到的ClassNotFoundException核心原因是加载类A的URLClassLoader被提前关闭了。你的loadClassFromJar方法用了try-with-resources创建ClassLoader,方法执行完离开try块时,这个ClassLoader会被自动关闭。虽然类A已经加载成功,但它依赖的类B还没被加载;当调用constructor.newInstance()实例化A时,JVM需要加载B,但此时原ClassLoader已经关闭,没法再从外部Jar里读取类B,直接抛出异常。

你提到的几个现象完全符合这个逻辑:

  • 调用aClass.getClasses()时,ClassLoader还没关闭,此时会触发相关依赖类的加载,后续实例化时就不用再加载了
  • 提前显式加载B,同样是趁ClassLoader还开着的时候把B加载进JVM,后续实例化A就不会出问题
  • 哪怕B是静态内部类,实例化A时还是需要加载B,而ClassLoader已经关了,所以问题依旧存在

可行解决方案

1. 不要提前关闭ClassLoader

去掉try-with-resources,让ClassLoader的生命周期和应用同步,或者在所有加载的类都不再使用时再手动关闭。修改后的代码:

private Class<?> loadClassFromJar(File jarFile, String className) throws IOException, ClassNotFoundException {
    URL jarUrl = jarFile.toURI().toURL();
    URLClassLoader ucl = new URLClassLoader(new URL[]{jarUrl}, this.getClass().getClassLoader());
    return Class.forName(className, true, ucl);
}

注意:这种方式要记得在合适时机手动关闭ClassLoader,防止内存泄漏。

2. 提前加载所有依赖类

在ClassLoader关闭前,把类A需要的所有依赖类(比如B)都显式加载一遍,确保它们已经被JVM加载。修改方法如下:

private Class<?> loadClassFromJar(File jarFile, String className, String... dependentClasses) throws IOException, ClassNotFoundException {
    URL jarUrl = jarFile.toURI().toURL();
    try (URLClassLoader ucl = new URLClassLoader(new URL[]{jarUrl}, this.getClass().getClassLoader())) {
        // 先加载所有依赖类
        for (String depClass : dependentClasses) {
            ucl.loadClass(depClass);
        }
        // 再加载目标类A
        return Class.forName(className, true, ucl);
    }
}

调用时传入B的全类名:

Constructor<?> constructor = loadClassFromJar(jarFile, className, "com.x.y.B").getConstructor(argsClasses);
constructor.newInstance(argsInstances);

3. 自定义ClassLoader并保留引用

如果需要更灵活的类加载管理,可以自定义ClassLoader,保留它的引用,避免被自动关闭:

public class JarClassLoader extends URLClassLoader {
    public JarClassLoader(URL url, ClassLoader parent) {
        super(new URL[]{url}, parent);
    }
}

// 成员变量保留ClassLoader引用
private JarClassLoader jarClassLoader;

private Class<?> loadClassFromJar(File jarFile, String className) throws IOException, ClassNotFoundException {
    URL jarUrl = jarFile.toURI().toURL();
    jarClassLoader = new JarClassLoader(jarUrl, this.getClass().getClassLoader());
    return Class.forName(className, true, jarClassLoader);
}

// 程序退出或不再需要时关闭
public void cleanUpClassLoader() {
    if (jarClassLoader != null) {
        try {
            jarClassLoader.close();
        } catch (IOException e) {
            // 按需处理异常
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:20:04