【发布时间】:2017-07-08 14:51:13
【问题描述】:
我正在尝试从 JAR 加载一个在运行时表示为 byte[] 数组的类。
我知道关于要加载的类的两件事:
1.它实现了“RequiredInterface”
2. 我知道它的限定名称:“sample.TestJarLoadingClass”
我找到了solution,我必须在其中扩展 ClassLoader 但它会抛出:
Exception in thread "main" java.lang.ClassNotFoundException: sample.TestJarLoadingClass
at java.lang.ClassLoader.findClass(ClassLoader.java:530)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at tasks.Main.main(Main.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
每当我想加载课程时。
这种情况可能是什么原因,我该如何摆脱这种情况?
任何帮助都非常感谢
主要方法:
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
Path path = Paths.get("src/main/java/tasks/sample.jar");
RequiredInterface requiredInterface = (RequiredInterface) Class.forName("sample.TestJarLoadingClass", true, new ByteClassLoader(Files.readAllBytes(path))).newInstance();
}
自定义类加载器:
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ByteClassLoader extends ClassLoader {
private final byte[] jarBytes;
private final Set<String> names;
public ByteClassLoader(byte[] jarBytes) throws IOException {
this.jarBytes = jarBytes;
this.names = loadNames(jarBytes);
}
private Set<String> loadNames(byte[] jarBytes) throws IOException {
Set<String> set = new HashSet<>();
try (ZipInputStream jis = new ZipInputStream(new ByteArrayInputStream(jarBytes))) {
ZipEntry entry;
while ((entry = jis.getNextEntry()) != null) {
set.add(entry.getName());
}
}
return Collections.unmodifiableSet(set);
}
@Override
public InputStream getResourceAsStream(String resourceName) {
if (!names.contains(resourceName)) {
return null;
}
boolean found = false;
ZipInputStream zipInputStream = null;
try {
zipInputStream = new ZipInputStream(new ByteArrayInputStream(jarBytes));
ZipEntry entry;
while ((entry = zipInputStream.getNextEntry()) != null) {
if (entry.getName().equals(resourceName)) {
found = true;
return zipInputStream;
}
}
} catch (IOException e) {;
e.printStackTrace();
} finally {
if (zipInputStream != null && !found) {
try {
zipInputStream.close();
} catch (IOException e) {;
e.printStackTrace();
}
}
}
return null;
}
}
必需接口:
public interface RequiredInterface {
String method();
}
JAR 文件中的类:
package sample;
public class TestJarLoadingClass implements RequiredInterface {
@Override
public String method() {
return "works!";
}
}
【问题讨论】:
-
我使用了您在我的机器上发布的代码并且一切正常。您能否发布确切的例外情况?另外请检查您使用的路径是否真的指向包含您要加载的类的jar?
-
好的,我发布了整个异常消息。我检查了所有可能的“愚蠢”错误,一切都应该正常。请检查您的类加载器范围内是否没有需要加载的类。
-
是的,你是对的,我错误地添加了对 jar 的依赖项,而不是使用接口的 jar。对不起
-
为什么不直接使用 URLClassLoader,而不是从头开始重新实现呢?为什么不一开始就把那个 jar 放在类路径中呢?
-
因为它需要我将 JAR 存储在本地。在实际情况下,我的输入是来自应用程序前端的 byte[] 数组,我不希望在本地构建 JAR 文件并仅基于 byte[] 制作解决方案。
标签: java class classloader dynamic-class-loaders