Java类加载导致父类

时间:2016-03-01 15:05:12

标签: java classloader

我目前正在为Java程序制作一个小插件框架。 基本上GRPluginManager.loadPlugins()循环遍历目录中的所有jar文件,然后从jar内部的特定文件中读取此插件的Main-class的名称,并将其加载到类路径中。之后,它会调用此插件-Elass类的enable()方法(扩展GRPlugin)。

然而,它不起作用。看起来插件-Main-class的加载工作正常,只能找到父类(GRPlugin)。但它肯定存在。

GRPlugin.java

package io.github.grengine.core.plugins;

public class GRPlugin {

    public void enable(){

    }

    public void disable(){

    }
}

GRPluginManager.java

package io.github.grengine.core.plugins;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.bukkit.plugin.java.JavaPluginLoader;
import org.yaml.snakeyaml.Yaml;

import io.github.grengine.JarUtils;
import io.github.grengine.Log;
import io.github.grengine.Main;

public class GRPluginManager {

    private static final String PLUGIN_PATH = Main.main.getDataFolder()+File.separator+"storage"+File.separator+"plugins";
    private ArrayList<GRPlugin> plugins = new ArrayList<GRPlugin>();

    public ArrayList<GRPlugin> loadPlugins() throws Exception{

    File filePath = new File(PLUGIN_PATH);
    File files [] = filePath.listFiles();

    //Iterate over files in the plugin directory

    for(File file:files){
        if(file.isFile()){

            Log.Info("Reading "+file);

            ZipFile zipFile = new ZipFile(file);


            String fullyQualifiedName = null;
            String plname = null;
            String plversion = null;

            Enumeration<? extends ZipEntry> entries = zipFile.entries();

            while (entries.hasMoreElements()) {
                ZipEntry ze = (ZipEntry) entries.nextElement();
                if(ze.getName().equals("gre"+File.separator+"ext.yml")){
                    Yaml yaml = new Yaml();
                    InputStream is = zipFile.getInputStream(ze);
                    Map<?, ?> map = (Map<?, ?>) yaml.load(is);

                    fullyQualifiedName = (String) map.get("main");
                    plname = (String) map.get("name");
                    plversion = (String) map.get("version");
                }
            }


            zipFile.close();


            Log.Info("Enabling "+plname+" "+plversion+" ...");

            URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { new URL("file:"+file) });


            Class<?> clazz = classLoader.loadClass(fullyQualifiedName);
            GRPlugin pl = (GRPlugin) clazz.newInstance();
            pl.enable();

Log.Info("Enabling "+plname+" "+plversion+" ...");

        }else {
         //skip folders
         continue;
       }
    }
    return plugins;
    }

}

插件的Main类(扩展GRPlugin)/ Main.java

的类
package io.github.plutos;

import io.github.grengine.Log;
import io.github.grengine.core.plugins.GRPlugin;

public class Main extends GRPlugin{

    @Override
    public void enable() {
        Log.Info("ENABLED");

    }

    @Override
    public void disable() {
        Log.Info("DISABLED");

    }

}

这是stacktrace:

java.lang.NoClassDefFoundError: io/github/grengine/core/plugins/GRPlugin
        at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_05]
        at java.lang.ClassLoader.defineClass(ClassLoader.java:760) ~[?:1.8.0_05]
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[?:1.8.0_05]
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:455) ~[?:1.8.0_05]
        at java.net.URLClassLoader.access$100(URLClassLoader.java:73) ~[?:1.8.0_05]
        at java.net.URLClassLoader$1.run(URLClassLoader.java:367) ~[?:1.8.0_05]
        at java.net.URLClassLoader$1.run(URLClassLoader.java:361) ~[?:1.8.0_05]
        at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_05]
        at java.net.URLClassLoader.findClass(URLClassLoader.java:360) ~[?:1.8.0_05]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_05]
        at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:798) ~[?:1.8.0_05]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_05]
        at io.github.grengine.core.plugins.GRPluginManager.loadPlugins(GRPluginManager.java:82) ~[?:?]
        at io.github.grengine.Main.onEnable(Main.java:56) ~[?:?]
        at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:321) ~[spigot-core.jar:git-Spigot-c5146ba-c637b93]
        at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:340) [spigot-core.jar:git-Spigot-c5146ba-c637b93]
        at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:405) [spigot-core.jar:git-Spigot-c5146ba-c637b93]
        at org.bukkit.craftbukkit.v1_8_R3.CraftServer.loadPlugin(CraftServer.java:356) [spigot-core.jar:git-Spigot-c5146ba-c637b93]
        at org.bukkit.craftbukkit.v1_8_R3.CraftServer.enablePlugins(CraftServer.java:316) [spigot-core.jar:git-Spigot-c5146ba-c637b93]
        at net.minecraft.server.v1_8_R3.MinecraftServer.s(MinecraftServer.java:418) [spigot-core.jar:git-Spigot-c5146ba-c637b93]
        at net.minecraft.server.v1_8_R3.MinecraftServer.k(MinecraftServer.java:382) [spigot-core.jar:git-Spigot-c5146ba-c637b93]
        at net.minecraft.server.v1_8_R3.MinecraftServer.a(MinecraftServer.java:337) [spigot-core.jar:git-Spigot-c5146ba-c637b93]
        at net.minecraft.server.v1_8_R3.DedicatedServer.init(DedicatedServer.java:256) [spigot-core.jar:git-Spigot-c5146ba-c637b93]
        at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:528) [spigot-core.jar:git-Spigot-c5146ba-c637b93]
        at java.lang.Thread.run(Thread.java:745) [?:1.8.0_05]
Caused by: java.lang.ClassNotFoundException: io.github.grengine.core.plugins.GRPlugin
        at java.net.URLClassLoader$1.run(URLClassLoader.java:372) ~[?:1.8.0_05]
        at java.net.URLClassLoader$1.run(URLClassLoader.java:361) ~[?:1.8.0_05]
        at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_05]
        at java.net.URLClassLoader.findClass(URLClassLoader.java:360) ~[?:1.8.0_05]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_05]
        at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:798) ~[?:1.8.0_05]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_05]
        ... 25 more

我找不到解决此问题的方法,我已尝试过不同的ClassLoaders(ClassLoader.getSystemClassLoader()GRPlugin.class.getClassLoader())...

你能说出我做错了什么吗?如果您需要更多信息,请随时提出!

提前致谢, fusionlightcat

2 个答案:

答案 0 :(得分:4)

如果未将父类加载器设置为自定义类加载器,则系统类加载器将默认用作父类。

似乎在您的环境中GRPlugin由系统类加载器的后代加载,因而错误。

请改用:

URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { new URL("file:"+file) }, GRPlugin.class.getClassLoader());

答案 1 :(得分:1)

您可以在ipscan开源项目中看到插件系统实现。以下是探索的起点:

  • Plugin界面。 ipscan中的任何插件都必须实现它。
  • PluginLoader类是您的<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <div id="text"></div>类比。它从不同的地方加载插件(在项目jar,外部jar等中)。在这里查看GRPluginManager的实现,它扩展PluginClassLoader并从jar文件加载类。
  • feeders文件夹,其中包含一些实现了URLClassLoader接口的inproject插件。

更新:您也可以重复使用您的插件系统标准java.util.ServiceLoader或某些alternative solution