创建一个ClassLoader以从字节数组加载JAR文件


问题内容

我正在寻找编写一个自定义类加载器,它将JAR通过自定义网络加载文件。最后,我要做的只是JAR文件的字节数组。

我无法将字节数组转储到文件系统上并使用URLClassLoader
我的第一个计划是JarFile从流或字节数组创建对象,但它仅支持File对象。

我已经写了一些使用的东西JarInputStream

public class RemoteClassLoader extends ClassLoader {

    private final byte[] jarBytes;

    public RemoteClassLoader(byte[] jarBytes) {
        this.jarBytes = jarBytes;
    }

    @Override
    public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        Class<?> clazz = findLoadedClass(name);
        if (clazz == null) {
            try {
                InputStream in = getResourceAsStream(name.replace('.', '/') + ".class");
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                StreamUtils.writeTo(in, out);
                byte[] bytes = out.toByteArray();
                clazz = defineClass(name, bytes, 0, bytes.length);
                if (resolve) {
                    resolveClass(clazz);
                }
            } catch (Exception e) {
                clazz = super.loadClass(name, resolve);
            }
        }
        return clazz;
    }

    @Override
    public URL getResource(String name) {
        return null;
    }

    @Override
    public InputStream getResourceAsStream(String name) {
        try (JarInputStream jis = new JarInputStream(new ByteArrayInputStream(jarBytes))) {
            JarEntry entry;
            while ((entry = jis.getNextJarEntry()) != null) {
                if (entry.getName().equals(name)) {
                    return jis;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

这对于小型JAR文件可能很好用,但是我尝试加载2.7MB包含几乎所有2000类的jar文件,它160 ms只是为了遍历所有条目而已,更不用说加载找到的类了。

如果有人知道一个解决方案比JarInputStream每次加载类都遍历一个项更快的方法,请分享!


问题答案:

我将遍历该类一次并缓存条目。我还将查看URLClassLoader的源代码以了解其功能。如果失败,则将数据写入临时文件并通过普通的类加载器加载。