首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从内存动态加载JAR

从内存动态加载JAR
EN

Stack Overflow用户
提问于 2015-03-10 21:02:57
回答 4查看 4K关注 0票数 7

我想要动态加载一个JAR,直接用于内存。

比方说,我有一个包含JAR的缓冲区,我想加载JAR中的所有类,或者至少列出JAR中存在的所有文件。(类、图像等)。

例如,如果我加载的第一个类依赖于第二个类,我该怎么办?java知道如何处理这个问题吗?还是我一个人搞定这件事?

EN

回答 4

Stack Overflow用户

发布于 2015-03-11 18:32:02

既然您说过“至少列出JAR中存在的所有文件”,那么让我们从这个相当简单的任务开始吧。

假设您的JarFile在一个字节数组byte[] buffer

代码语言:javascript
复制
try(JarInputStream is=new JarInputStream(new ByteArrayInputStream(buffer))) {
    for(;;) {
        JarEntry nextEntry = is.getNextJarEntry();
        if(nextEntry==null) break;
        System.out.println(nextEntry);
    }
}

因为标准的ClassLoader实现依赖于JarFile实现,而后者依赖于物理文件而不是抽象,所以从这样的表示中加载类不能开箱即用。

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

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

代码语言:javascript
复制
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 »);
}
票数 9
EN

Stack Overflow用户

发布于 2015-03-10 21:24:41

您可能需要先将jar写入磁盘,然后才能使用以下命令将其添加到类路径中:(full answer here)

代码语言:javascript
复制
URLClassLoader child = new URLClassLoader (myJar.toURL(), this.getClass().getClassLoader());
Class classToLoad = Class.forName ("com.MyClass", true, child);
Method method = classToLoad.getDeclaredMethod ("myMethod");
Object instance = classToLoad.newInstance ();
Object result = method.invoke (instance);

如果要枚举不在类路径中的jar的内容,可以始终将其视为压缩文件:(see full answer here)

代码语言:javascript
复制
ZipFile zipFile = new ZipFile("testfile.zip");
Enumeration zipEntries = zipFile.entries();
String fname;
while (zipEntries.hasMoreElements()) {
    fname = ((ZipEntry)zipEntries.nextElement()).getName();
}
票数 1
EN

Stack Overflow用户

发布于 2015-03-10 21:12:43

您应该使用自定义的 ClassLoader ,并将JAR文件设置为其类路径。

类总是延迟加载的,您不必显式地加载它们。一旦JAR位于ClassLoader的类路径上,您就可以解析资源了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28964450

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档