我正在尝试开发一个插件系统,它提供了一个在运行时加载jar的接口。每个jar都包含一个从公共抽象类扩展的类。例如:
//BasicPlugin.java
package byv;
abstract class BasicPlugin {
abstract public int test(int a);
}
我实现了一个子类:
//PluginA.java
package byv;
import byv.BasicPlugin;
public class PluginA extends BasicPlugin {
@Override
public int test(int a) {
return a + a;
}
}
上面的子类被编译并打包到一个jar文件(PluginA.jar)中。这个jar只包含PluginA.class。然后在主项目中我使用URLClassLoader加载它:
private static void loadTest() throws Exception {
URL url = new File("PluginA.jar").toURI().toURL();
URLClassLoader ClassLoader = URLClassLoader.newInstance(new URL[] {url});
Class<?> clazz = Class.forName("byv.PluginA", true, ClassLoader);
BasicPlugin obj = (BasicPlugin) clazz.newInstance();
obj.test(2);
}
我已经在主项目中添加了对BasicPlugin的引用。但错误仍然存在:
Exception in thread "main" java.lang.IllegalAccessError: class byv.PluginA cannot access its superclass byv.BasicPlugin
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:277)
at java.net.URLClassLoader.access$000(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:212)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:615)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at byv.Main.loadTest1(Main.java:18)
at byv.Main.main(Main.java:11)
那么我该如何解决这个问题?
答案 0 :(得分:1)
由于它是IllegalAccessError,我建议您公开BasicPlugin来解决问题。 Afaik你定义的类是包保护的。因此,无法从不同的类加载器访问它。既然这就是你的插件所需要的,那么让这个类不是公共的就是没有意义的。 还有一件事,URLClassLoader有第二个构造函数,您可以在其中指定父加载器。然后使用此加载器加载插件类。在更复杂的环境中,您可能希望指定该加载器。目前你的代码使用或多或少的系统加载器,在你的例子中没问题,但我不知道你打算以后做什么。 BasicPlugin.class.getClassLoader()肯定会为该类提供正确的加载器。
答案 1 :(得分:1)
传递类加载器上下文以在构造URLClassLoader
实例时使用:
URLClassLoader ClassLoader = URLClassLoader.newInstance(new URL[] {url},
this.getClassLoader());