尝试为我的应用程序实现一个插件系统,其代码扩展了我的Plugin类以定义自定义功能。
这个代码从jar中加载一个类,与应用程序的.jar在同一个目录中,可以正常工作:
if(pluginName.endsWith(".jar"))
{
JarFile jarFile = new JarFile(pluginName);
Enumeration jarComponents = jarFile.entries();
while (jarComponents.hasMoreElements())
{
JarEntry entry = (JarEntry) jarComponents.nextElement();
if(entry.getName().endsWith(".class"))
{
className = entry.getName();
}
}
File file = new File(System.getProperty("user.dir")+"/"+pluginName);
URLClassLoader loader = new URLClassLoader(new URL[]{file.toURI().toURL()});
Class newClass = Class.forName(className.replace(".class", ""), true, loader);
newPlugin = (Plugin) newClass.newInstance();
}
这导致正确的响应:
benpalmer$ java -jar assignment.jar test_subproject.jar
- INFO: Add new plugin: source.com
问题是我还想为用户提供指定.class文件的选项,因为这实际上是为了我的插件系统而打包到.jar中的所有内容。
else if(pluginName.endsWith(".class"))
{
File file = new File(System.getProperty("user.dir")+"/"+pluginName);
URLClassLoader loader = new URLClassLoader(new URL[]{file.toURI().toURL()});
Class newClass = Class.forName(className.replace(".class", ""), true, loader);
newPlugin = (Plugin) newClass.newInstance();
}
... exception handling
结果如下:
benpalmer$ java -jar assignment.jar TestPlugin.class
SEVERE: Error: Plugin class not found. Class name:
java.lang.ClassNotFoundException:
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at newsfeed.model.Plugin.loadClassFromJarFile(Plugin.java:144)
at newsfeed.controller.NFWindowController.initPlugins(NFWindowController.java:81)
at newsfeed.controller.NewsFeed$1.run(NewsFeed.java:20)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
我已经尝试了上面的代码和路径名/其他选项的许多变体,但每次都得到ClassNotFoundException。最初加载罐子时遇到了麻烦但是使用了固定的完全限定路径,现在我无法加载类。
有什么想法吗? :)
答案 0 :(得分:1)
这是URLClassLoader的一个功能,它适用于类的目录(您可以将.jar
视为打包目录)。
您使用的constructor具有以下javadoc
使用默认委托父ClassLoader为指定的URL构造一个新的URLClassLoader。首次在父类加载器中搜索后,将按照为类和资源指定的顺序搜索URL。任何以“/”结尾的URL都被假定为引用目录。否则,假定URL引用JAR文件,该文件将根据需要下载和打开。
如果您绝对想要为每个单独的类创建类加载器,则应考虑对SecureClassLoader
进行子类化并使用defineClass
方法手动定义新类。
The basics of Java class loaders文章对您有所帮助。
答案 1 :(得分:1)
再次看到我的问题并意识到我忘了发布我发现问题的解决方案。我希望这可以帮助将来的某个人,因为这是我遇到的唯一一个工作案例 - 大学任务问题。我简直不敢相信这很简单:
byte[] classData = Files.readAllBytes(Paths.get(fileName));
Class<?> cls = defineClass(null, classData, 0, classData.length);
return (PluginClassName)cls.newInstance();