ServiceLoader.next导致NoClassDefFoundError

时间:2013-04-30 08:05:43

标签: java noclassdeffounderror serviceloader

我问,因为我完全确定我做了正确的事。我正在使用Eclipse进行Web项目。我们在包com.web.project中将其称为WebProject(duh)。

我希望WebProject在运行时加载JAR插件,所以我想我可以利用java.util.ServiceLoader。所以我在WebProject项目中创建了一个接口com.web.project.WebProjectPlugin,其中包含了插件必须实现的所有方法。

然后我创建了项目PluginProject,在其Build路径中将WebProbject / build / classes添加为类文件夹:

package com.web.project.plugin;

import com.web.project.WebProjectPlugin;

public class TestPlugin implements WebProjectPlugin {
    // Implementation of the interface methods...
}

然后我在插件项目中创建了一个META-INF / services文件夹,将文本文件com.web.project.WebProjectPlugin放在里面,包含唯一的行“com.web.project.plugin.TestPlugin”。

我导出了JAR文件,检出了添加的build / classes文件夹并将其放在硬盘中的某个位置。当WebProject启动时,它会执行以下操作:

File[] jlist = pluginsDir.listFiles(new FileFilter() {
    public boolean accept(File file) {
        return file.getPath().toLowerCase().endsWith(".jar");
    }
});
URL[] urls = new URL[jlist.length];
for (int i = 0; i < jlist.length; i++)
    urls[i] = jlist[i].toURI().toURL();
URLClassLoader ucl = new URLClassLoader(urls);

ServiceLoader<WebProjectPlugin> srvl =
    ServiceLoader.load(WebProjectPlugin.class, ucl);
Iterator<WebProjectPlugin> iter = srvl.iterator();
while (iter.hasNext()) {
    WebProjectPlugin plugin = iter.next();
    plugins.add(plugin);
}

pluginsDir是一个File对象,指向JAR文件所在的目录。首先,似乎srvl完成了它的工作,因为iter不为空,但是当它达到NoClassDefFoundError时会抛出可怕的iter.next()

我已经设法创建了一个插件管理器项目来测试ServiceLoader,它运行得很好,但它是一个普通的控制台Java应用程序,而不是一个Web项目。那么,我在这里做错了什么?

我有点困惑:它怎么能找到com.web.project.WebProjectPlugin的类定义,因为它在同一个正在运行的项目中?是否与我正在使用的URLClassLoader对象有关?

这是stack trace

1 个答案:

答案 0 :(得分:6)

尝试将父类加载器分配给URLClassLoader

URLClassLoader loader = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());

WebProject需要类加载器的某个层次结构,因此如果未正确设置父/子符号,则可能是您的类彼此不可见。