我正在编写一个插件加载器 - 它加载不在类路径上的jar。我写了一个简单的自定义ClassLoader,它在其构造函数中接受一个JarFile,并在JarFile中查找指定的类。这个加载器只是覆盖ClassLoader的findClass()
方法,并且工作正常。
然后我确定我还需要能够从插件jar获取资源。所以我覆盖了findResource()
。这有意外的结果导致基本插件类无法在jar中找到其他类:我得到NoClassDefFoundErrors!
换句话说,如果我有包含MyPlugin和MyPluginComponent的plugin.jar:
findResource()
,那么我可以加载jar,创建一个MyPlugin实例,然后又可以创建一个MyPluginComponent。但是我找不到捆绑在jar中的资源。findResource()
,那么我可以加载jar,创建MyPlugin的实例,但如果MyPlugin尝试创建MyPluginComponent,我会得到NoClassDefFoundError。这表明findResource()的实现无论如何都找不到类文件 - 但它甚至没有被调用(根据我的日志记录),所以我不知道是怎么回事。这种互动如何解决,我该如何解决?
我尝试编写一个小的自包含示例,并且遇到困难,手动生成一个不会产生“不兼容的幻数”错误的jar文件。希望无论我做错什么,单从类加载器就可以看出来。很抱歉给您带来不便,感谢您抽出宝贵时间。
import com.google.common.io.CharStreams;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.lang.ClassLoader;
import java.net.URL;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* Custom class loader for loading plugin classes. Adapted from
* http://kalanir.blogspot.com/2010/01/how-to-write-custom-class-loader-to.html
*/
public static class PluginLoader extends ClassLoader {
private JarFile jarFile_;
public PluginLoader(JarFile jarFile) {
super(Thread.currentThread().getContextClassLoader());
jarFile_ = jarFile;
}
@Override
public Class findClass(String className) {
try {
// Replace "." with "/" for seeking through the jar.
String classPath = className.replace(".", "/") + ".class";
System.out.println("Searching for " + className + " under " + classPath);
JarEntry entry = jarFile_.getJarEntry(classPath);
if (entry == null) {
return null;
}
InputStream stream = jarFile_.getInputStream(entry);
String contents = CharStreams.toString(
new InputStreamReader(stream));
stream.close();
byte[] bytes = contents.getBytes();
Class result = defineClass(className, bytes, 0, bytes.length);
return result;
}
catch (IOException e) {
System.out.println(e + "Unable to load jar file " + jarFile_.getName());
}
catch (ClassFormatError e) {
System.out.println(e + "Unable to read class data for class " + className + " from jar " + jarFile_.getName());
}
return null;
}
@Override
protected URL findResource(String name) {
System.out.println("Asked to find resource at " + name);
try {
String base = new File(jarFile_.getName()).toURI().toURL().toString();
URL result = new URL(String.format("jar:%s!/%s", base, name));
System.out.println("Result is " + result);
return result;
}
catch (IOException e) {
System.out.println(e + "Unable to construct URL to find " + name);
return null;
}
}
@Override
public InputStream getResourceAsStream(String name) {
System.out.println("Getting resource at " +name);
JarEntry entry = jarFile_.getJarEntry(name);
if (entry == null) {
System.out.println("Couldn't find resource " + name);
return null;
}
try {
return jarFile_.getInputStream(entry);
}
catch (IOException e) {
System.out.println(e + "Unable to load resource " + name + " from jar file " + jarFile_.getName());
return null;
}
}
}
答案 0 :(得分:0)
如果您的要求只是阅读额外的JAR文件,那么延长public class PluginLoader extends URLClassLoader {
public PluginLoader(String jar) throws MalformedURLException {
super(new URL[] { new File(jar).toURI().toURL() });
}
}
可能是更好的选择。
script.pl(filename)