我编写了一个应用程序来管理几个以jar形式提供的插件。我使用URLClassLoader
加载插件类,它按预期工作。
但是现在我正在编写一个插件,它会加载一些存储在jar中的资源。如果我将此插件作为独立应用程序启动,一切正常,但如果我从应用程序内部启动它,当我尝试打开资源NullPointerException
时,我会得到InputStream
。
我打开这样的流:
this.getClass().getResourceAsStream("/templates/template.html");
我的Eclipse项目结构如下:
src
|
+ My source files
resources
|
+ templates
|
+ template.html
以下加载我的插件:
private List<Class<?>> loadClasses(final File[] jars) {
List<Class<?>> classes = new ArrayList<Class<?>>();
URL[] urls = getJarURLs(jars);
URLClassLoader loader = new URLClassLoader(urls);
for (File jar : jars) {
JarFile jarFile = null;
try {
jarFile = new JarFile(jar);
} catch (IOException e) {
// Skip this jar if it can not be opened
continue;
}
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (isClassFile(entry.getName())) {
String className = entry.getName().replace("/", ".").replace(".class", "");
Class<?> cls = null;
try {
cls = loader.loadClass(className);
} catch (ClassNotFoundException e) {
// Skip this jar if a class inside it can not be loaded
continue;
}
classes.add(cls);
}
}
try {
jarFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
loader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return classes;
}
/**
* Checks if a path points to a class file or not.
*
* @param path the filename to check
* @return {@code true} if the path points to a class file or {@code false}
* if not
*/
private boolean isClassFile(final String path) {
return path.toLowerCase().endsWith(".class") && !path.toLowerCase().contains("package-info");
}
然后我使用newInstance()
从这些类中创建实例。
我认为插件jar的根路径与应用程序的根路径不同,或者没有加载jar文件的所有内容,或者两者都是......
有人可以帮助我吗?
答案 0 :(得分:1)
首先请注意,使用getClass().getResource(...)
也会委托ClassLoader
,URLClassLoader
也负责加载资源。使用哪个类加载器?它与加载类的类加载器相同。点。
在您的代码中,您构建了一个URLClassLoader
来加载某些类。因此,如果上面提到的调用来自插件中的类,则相同的loadClass
将用于加载资源。
这一切似乎都没问题......但你犯了一点错误。在加载结束时,您还关闭了加载程序。这样可以防止后续调用getResource
或URLClassLoader
返回任何有意义的内容。实际上,它可能为null,因为现在加载器无法再加载资源了。
结论:如果您仍需要加载目的,请不要关闭{{1}}。而是保持对此类加载器的引用,并在程序运行时结束时将其关闭。