简体   繁体   English

如何在运行时从jar从工作目录加载.class?

[英]How to load .class from working directory at runtime from jar?

Attempting to implement a plugin system for my application, the code of which extends my Plugin class to define custom functionality. 尝试为我的应用程序实现一个插件系统,其代码扩展了我的Plugin类以定义自定义功能。

This code to load a class from within a jar, in the same directory as the .jar of the application, works fine: 此代码可以从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();
}

Which results in the correct response of: 导致正确的响应:

benpalmer$ java -jar assignment.jar test_subproject.jar
- INFO: Add new plugin: source.com

The issue is I also want to provide the user the option to specify a .class file instead, as that is realistically all that is packed into a .jar for the purposes of my plugin system. 问题是我还想向用户提供选项来指定.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

Which results in the following: 结果如下:

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)

I've tried the code above and many variations of path names/other options, but get ClassNotFoundException every time. 我已经尝试了上面的代码以及路径名/其他选项的许多变体,但是每次都得到ClassNotFoundException。 Originally had trouble loading the jars but using the fully qualified path fixed that, now I can't load the Classes. 最初在加载罐子时遇到了麻烦,但是使用了完全限定的路径进行了修复,现在我无法加载类。

Any ideas? 有任何想法吗? :) :)

This is a feature of URLClassLoader it works with directories of classes (you may assume .jar as packed directory). 这是URLClassLoader的一项功能,它可用于类目录(您可以将.jar视为打包目录)。

The constructor you are using has the following javadoc 您使用的构造函数具有以下javadoc

Constructs a new URLClassLoader for the specified URLs using the default delegation parent ClassLoader. 使用默认的委托父类ClassLoader为指定的URL构造一个新的URLClassLoader。 The URLs will be searched in the order specified for classes and resources after first searching in the parent class loader. 在首次在父类加载器中搜索后,将按照为类和资源指定的顺序搜索URL。 Any URL that ends with a '/' is assumed to refer to a directory. 假定任何以“ /”结尾的URL均指向目录。 Otherwise, the URL is assumed to refer to a JAR file which will be downloaded and opened as needed. 否则,假定该URL指向将要根据需要下载并打开的JAR文件。

If you absolutely want to create class loaders for each separate class you should consider subclassing SecureClassLoader and defining new class manually with defineClass method. 如果您绝对想为每个单独的类创建类加载器,则应考虑将SecureClassLoader子类化,并使用defineClass方法手动定义新类。

The basics of Java class loaders article should be of help to you. Java类加载器的基础知识应该对您有所帮助。

Saw my question again and realised I'd forgotten to post a solution I found to my problem. 再次看到我的问题,意识到我忘了发布找到的解决方案。 I hope this helps someone in the future, as it's the only working example I ever found for my situation - a university assignment problem. 我希望这对以后的人有所帮助,因为这是我针对自己的情况找到的唯一可行的例子-大学分配问题。 I can't believe it was this simple: 我简直不敢这么简单:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM