【问题标题】:How to load .class from working directory at runtime from jar?如何在运行时从 jar 中加载工作目录中的 .class?
【发布时间】:2018-04-02 11:01:46
【问题描述】:

尝试为我的应用程序实现一个插件系统,其代码扩展了我的 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。最初在加载 jar 时遇到问题,但使用完全限定路径修复了该问题,现在我无法加载类。

有什么想法吗? :)

【问题讨论】:

标签: java class reflection jar classloader


【解决方案1】:

再次看到我的问题并意识到我忘记发布我发现的问题的解决方案。我希望这对将来的某人有所帮助,因为这是我为我的情况找到的唯一可行的示例-大学作业问题。我不敢相信它是如此简单:

byte[] classData = Files.readAllBytes(Paths.get(fileName));
Class<?> cls = defineClass(null, classData, 0, classData.length); 
return (PluginClassName)cls.newInstance();

【讨论】:

  • 感谢发布您的解决方案。
【解决方案2】:

这是 URLClassLoader 的一个功能,它适用于类目录(您可以假设 .jar 是打包目录)。

您使用的constructor 具有以下javadoc

使用默认委托父 ClassLoader 为指定的 URL 构造一个新的 URLClassLoader。在第一次在父类加载器中搜索之后,将按照为类和资源指定的顺序搜索 URL。假设任何以“/”结尾的 URL 都指向一个目录。否则,假定 URL 指向将根据需要下载和打开的 JAR 文件。

如果您绝对想为每个单独的类创建类加载器,您应该考虑将SecureClassLoader 子类化并使用defineClass 方法手动定义新类。

The basics of Java class loaders的文章应该对你有所帮助。

【讨论】:

  • 在这里感谢您的建议。由于难以实现以及时间限制,我决定避免允许使用 .class 文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-07
  • 2011-12-02
  • 2023-03-10
  • 2019-06-23
  • 2014-07-30
  • 2014-10-29
  • 2016-03-13
相关资源
最近更新 更多