创建一个ClassLoader以从字节数组加载JAR文件 [英] Creating a ClassLoader to load a JAR file from a byte array

查看:130
本文介绍了创建一个ClassLoader以从字节数组加载JAR文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一个自定义类加载器,它将从自定义网络中加载 JAR 文件。最后,我必须使用的是 JAR 文件的字节数组。

I'm looking to write a custom class loader that will load a JAR file from across a custom network. In the end, all I have to work with is a byte array of the JAR file.

我无法将字节数组转储到文件系统上并使用 URLClassLoader

我的第一个计划是创建 JarFile 来自流或字节数组的对象,但它只支持文件对象。

I cannot dump the byte array onto the file system and use a URLClassLoader.
My first plan was to create a JarFile object from a stream or byte array, but it only supports a File object.

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

I've already written up something that uses a 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 jar文件,几乎 2000 类和它正在花费 160 ms 只是迭代所有条目,更不用说加载它找到的类。

This may work fine for small JAR files, but I tried loading up a 2.7MB jar file with almost 2000 classes and it was taking around 160 ms just to iterate through all the entries let alone load the class it found.

如果有人知道一个解决方案比每次加载一个类时迭代 JarInputStream 的条目更快,请分享!

If anyone knows a solution that's faster than iterating through a JarInputStream's entries each time a class is loaded, please share!

推荐答案

我将遍历该类一次并缓存条目。我还会看一下URLClassLoader的源代码,看看它是如何做到的。如果失败,将数据写入临时文件并通过普通的类加载器加载。

I would iterate through the class once and cache the entries. I would also look at the source code for URLClassLoader to see how it does it. If that fails, write the data to a temporary file and load it via the normal class loader.

这篇关于创建一个ClassLoader以从字节数组加载JAR文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆