【问题标题】:Load jar using bytearray, cant find nested classes使用 bytearray 加载 jar,找不到嵌套类
【发布时间】:2018-08-18 11:37:06
【问题描述】:

想法

我在byte[] 中有一个罐子 (postgresql-9.4.1208.jre7.jar)。我想在运行时加载、连接和运行一些基本的 SQL 命令。

实施

因此我创建了一个新的类加载器:

public class JarClassloader extends ClassLoader {

    public interface DriverProblemReporter {
        void reportDriverProblem(String name, Throwable e);
    }

    private final byte[] driverdata;

    private final DriverProblemReporter problemReporter;

    public JarClassloader(byte[] jar, String drivername, DriverProblemReporter reporter) {
        super(ClassLoader.getSystemClassLoader());
        this.problemReporter = reporter;

        try {
            JarInputStream jis = new JarInputStream(new ByteArrayInputStream(jar));
            JarEntry entry = jis.getNextJarEntry();
            while (entry != null) {
                handleEntry(entry, jis);
                entry = jis.getNextJarEntry();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        this.driverdata = jar;
    }

    private void handleEntry(JarEntry entry, JarInputStream jis) {
        if (!entry.isDirectory()) {
            ByteArrayOutputStream baos;
            try {
                baos = new ByteArrayOutputStream();
                IOUtils.copy(jis, baos);
                baos.flush();
            } catch (IOException e) {
                problemReporter.reportDriverProblem(entry.getName(), e);
                return;
            }
            try {
                defineClass(baos.toByteArray(), 0, baos.size());
            } catch (LinkageError e) {
                problemReporter.reportDriverProblem(entry.getName(), e);
            }
        }
    }
}

Jar 加载成功,我可以获取 Driver 的实例。

兴趣点

在调用连接到数据库时出现此错误:

java.lang.NoClassDefFoundError: org/postgresql/hostchooser/HostRequirement$1
    at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:107)
    at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66)
    at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:215)
    at org.postgresql.Driver.makeConnection(Driver.java:406)
    at org.postgresql.Driver.connect(Driver.java:274)

在堆栈跟踪中,我看到 org.postgresql.Driver 的工作实例正在寻找一个名为 org/postgresql/hostchooser/HostRequirement$1 的类。

假设

我的JarClassloader 不加载匿名嵌套类。

问题

我应该怎么做才能成功加载jar中的所有类?

【问题讨论】:

  • 为什么你的 jar 是字节数组?那个字节数组是从哪里来的?如果它来自文件,则不应将其加载到字节数组中;您应该将文件的 URL 传递给 URLClassLoader。
  • @VGR 它不是来自文件。我可以编写一个 servlet,但应用程序服务器(tomcat)没有 http 连接器来服务 http 请求。我也可以写一个 url-protocol-handler,但这可能会带来安全问题。
  • 我会使用Files.createTempFile(null, ".jar"),然后是Files.write(tempFile, driverdata),然后是new URLClassLoader(new URL[] { tempFile.toUri().toURL() })。换句话说,将字节写入一个临时的 .jar 文件,并从该文件中创建一个标准的 ClassLoader。
  • @VGR 由于磁盘已满或权限无效,临时文件可能会被更改或不允许创建,并且可能会在进程终止后保留空间。同样通过设计,它将单一真实来源缓存到基于文件的缓存中。从技术上讲,jar 文件是真相的来源,通过设计,字节数组是真相的来源。单一事实来源要求技术来源和设计来源相同。
  • 你的推理可以应用于文件的所有使用。

标签: java jar classloader


【解决方案1】:

您需要按照类加载器需要它们的顺序加载类,而不是它们恰好在 JAR 文件中的顺序。因此,您需要重写 findClass() 方法并在该点搜索 JAR 文件以查找所请求的类。

使用文件会简单得多。

【讨论】:

    猜你喜欢
    • 2021-06-06
    • 2014-01-03
    • 2013-03-23
    • 1970-01-01
    • 2016-08-24
    • 1970-01-01
    • 2019-02-21
    • 2015-09-22
    • 1970-01-01
    相关资源
    最近更新 更多