从zip文件的子文件夹中的jar文件加载类

时间:2012-02-23 08:09:01

标签: java classloader

我有一个包含以下结构的zip文件

plugin
   data
      abc.jar
      xyz.jar

我想使用这些jar创建一个URLClassLoder实例。 一种方法是解压缩此文件,然后使用该文件系统路径创建URLClassLoaders。 我可以在记忆中做同样的事吗?

3 个答案:

答案 0 :(得分:1)

好的,你可以查看这个答案https://stackoverflow.com/a/2614154/90313

和此库http://truezip.java.net/

您可以一起使用它们来实现所需的功能。

答案 1 :(得分:0)

以下是有效的解决方案。您可以根据需要进行修改。

打开拉链的参考:recursively unzip archive in memory

有关类加载的参考:Java: How to load Class stored as byte[] into the JVM?

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public final class ZippedJarClassReader {

    private final static String JAR_EXTENSION = ".jar";

    public static Map<String, byte[]> loadZip(final File file) throws IOException {
        final byte[]          bytes = Files.readAllBytes(file.toPath());
        final ByteArrayOutputStream baos  = new ByteArrayOutputStream();
        baos.write(bytes);
        return unzip(baos);
    }

    public static final Map<String, byte[]> unzip(final ByteArrayOutputStream baos) {
        final Map<String, byte[]> result = new HashMap<String, byte[]>();
        try(final ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(baos.toByteArray()))) {
            ZipEntry       entry;
            while ((entry = in.getNextEntry()) != null) {
                final ByteArrayOutputStream os = new ByteArrayOutputStream();
                if (!entry.isDirectory()) {
                    os.write(in.readAllBytes());
                    if (entry.getName().toLowerCase().endsWith(JAR_EXTENSION)) {
                        result.putAll(unzip(os));
                    } else if (entry.getName().toLowerCase().endsWith(".class")) {
                        result.put(entry.getName().replaceAll("/", ".").substring(0, entry.getName().length() - 6), os.toByteArray());
                    }
                }
            }
            return result;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;

public final class ZipClassLoader extends URLClassLoader {

    private final Map<String, byte[]> classes;

    public ZipClassLoader(URL[] urls, final File zipFile) throws IOException {
        super(urls);
        classes = ZippedJarClassReader.loadZip(zipFile);
    }

    @Override
    public final Class<?> findClass(String name) throws ClassNotFoundException {
        final byte[] bytes = classes.get(name);
        if(bytes != null) return defineClass(name, bytes, 0, bytes.length);
        return super.findClass(name);
    }
}

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.zip.ZipException;

public class Test {

    @SuppressWarnings("resource")
    public static void main(String[] args) throws ZipException, IOException, ClassNotFoundException {
        final File zipFile = new File("zipfile.zip");
        final URLClassLoader loader = new ZipClassLoader(new URL[] {}, zipFile);
        final Class<?> classz = loader.loadClass("org.util.nanolog.Test");
        System.out.println(classz);
    }
}

答案 2 :(得分:0)

好的,youtube.liveChatMessages().list(liveChatId=liveChatId,part="snippet") URI方案似乎不起作用,但nio可以。这是加载Jetifier(Android构建工具)而不解压缩所有内容的示例。

jar:

这可行,并成功从Jetifier中打个招呼。我使用JDK 13。