从内存动态加载 JAR [英] Loading a JAR dynamically from memory

查看:23
本文介绍了从内存动态加载 JAR的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想动态加载 JAR,直接用于内存.
比如说,我有一个包含 JAR 的缓冲区,我想加载 JAR 中的所有类,或者至少列出 JAR 中存在的所有文件.(类、图像等...).
例如,如果我加载的第一个类依赖于第二个类,我该怎么办?java知道如何处理吗?还是我自己来处理?

I want to load a JAR dynamically, straight for memory.
Say, I have a buffer that contains a JAR, and I want to load all the classes inside the JAR, or at least list all of the files that exist inside the JAR. (classes, images, etc...).
What do I do if the first class that I load depends on the second class, for example? Does java know how to handle this? Or I have take care of this by myself?

推荐答案

既然你说至少列出 JAR 中存在的所有文件",让我们从这个相当简单的任务开始.

Since you said "at least list all of the files that exist inside the JAR", let’s begin with that rather easy task.

假设,你的 JarFile 在一个字节数组中,byte[] 缓冲区:

Suppose, you have your JarFile in a byte array, byte[] buffer:

try(JarInputStream is=new JarInputStream(new ByteArrayInputStream(buffer))) {
    for(;;) {
        JarEntry nextEntry = is.getNextJarEntry();
        if(nextEntry==null) break;
        System.out.println(nextEntry);
    }
}

从这种表示加载类不能开箱即用,因为标准的 ClassLoader 实现依赖于依赖物理文件的 JarFile 实现而不是抽象.

Loading classes from such a representation doesn’t work out-of-the-box because the standard ClassLoader implementations rely on the JarFile implementation which relies on a physical file rather than an abstraction.

因此,除非您只是将缓冲区写入临时文件,否则归结为实现您自己的ClassLoader.由于 JRE 仅支持如上所示的流访问,因此您必须线性扫描以查找请求的资源/类或迭代一次并将条目存储到 Map 中.

So unless you simply write the buffer into a temporary file, it boils down to implement your own ClassLoader. Since the JRE supports only stream access as shown above, you will have to scan linearly to find a requested resource/class or iterate once and store the entries into a Map.

实现 ClassLoader 的一种替代方法是实现一个自定义的 URL 处理程序与 URLClassLoader 一起使用,这将任务减少到查找如上所述:

One alternative to implementing a ClassLoader is to implement a custom URL handler to use together with a URLClassLoader which reduces the task to the lookup as described above:

final Map<String,byte[]> map=new HashMap<>();
try(JarInputStream is=new JarInputStream(new ByteArrayInputStream(buffer))) {
    for(;;) {
        JarEntry nextEntry = is.getNextJarEntry();
        if(nextEntry==null) break;
        final int est=(int)nextEntry.getSize();
        byte[] data=new byte[est>0? est: 1024];
        int real=0;
        for(int r=is.read(data); r>0; r=is.read(data, real, data.length-real))
            if(data.length==(real+=r)) data=Arrays.copyOf(data, data.length*2);
        if(real!=data.length) data=Arrays.copyOf(data, real);
        map.put("/"+nextEntry.getName(), data);
    }
}
URL u=new URL("x-buffer", null, -1, "/", new URLStreamHandler() {
    protected URLConnection openConnection(URL u) throws IOException {
        final byte[] data = map.get(u.getFile());
        if(data==null) throw new FileNotFoundException(u.getFile());
        return new URLConnection(u) {
            public void connect() throws IOException {}
            @Override
            public InputStream getInputStream() throws IOException {
                return new ByteArrayInputStream(data);
            }
        };
    }
});
try(URLClassLoader cl=new URLClassLoader(new URL[]{u})) {
    cl.loadClass( « a class from your JarFile buffer »);
}

这篇关于从内存动态加载 JAR的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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