Java-动态加载类

Java-动态加载类,java,class,plugins,dynamic,classloader,Java,Class,Plugins,Dynamic,Classloader,我目前正在创建一个插件系统(我的第一次尝试),查看其他人的代码,我正试图拼凑我自己的类加载器,并从目录中加载插件(这些将是类文件) 我的问题是,每当我尝试用类加载器加载类时,类加载器都找不到插件中引用程序的任何导入。(即:MyClass扩展插件com.mgmc.plugins noclassdeffound)不同的命名空间 一些示例代码: 类加载器: /* * To change this template, choose Tools | Templates * and open the

我目前正在创建一个插件系统(我的第一次尝试),查看其他人的代码,我正试图拼凑我自己的类加载器,并从目录中加载插件(这些将是类文件)

我的问题是,每当我尝试用类加载器加载类时,类加载器都找不到插件中引用程序的任何导入。(即:MyClass扩展插件com.mgmc.plugins noclassdeffound)不同的命名空间

一些示例代码: 类加载器:

/*


* To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.mcgm.game.provider;

import com.mcgm.utils.Misc;
import com.mcgm.utils.Paths;
import java.awt.AWTPermission;
import java.io.*;
import java.net.MalformedURLException;
import java.net.SocketPermission;
import java.net.URL;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.Permissions;
import java.security.ProtectionDomain;
import java.util.PropertyPermission;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Tom
 */
public class GameClassLoader extends ClassLoader {
private final ProtectionDomain domain;
private final URL base;

public GameClassLoader(final URL url) {
    base = url;
    final CodeSource codeSource = new CodeSource(base, (CodeSigner[]) null);
    domain = new ProtectionDomain(codeSource, getPermissions());
}

public void loadGames() {
    for (File f : Paths.compiledFolder.listFiles()) {
        try {
            Class c = loadClass(f.getPath());
            Misc.outPrint(c.getName());
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(GameClassLoader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

private Permissions getPermissions() {
    final Permissions ps = new Permissions();
    ps.add(new AWTPermission("accessEventQueue"));
    ps.add(new PropertyPermission("user.home", "read"));
    ps.add(new PropertyPermission("java.vendor", "read"));
    ps.add(new PropertyPermission("java.version", "read"));
    ps.add(new PropertyPermission("os.name", "read"));
    ps.add(new PropertyPermission("os.arch", "read"));
    ps.add(new PropertyPermission("os.version", "read"));
    ps.add(new SocketPermission("*", "resolve"));
    ps.add(new FilePermission(Paths.compiledFolder.getPath(), "read,write,delete"));
    ps.setReadOnly();
    return ps;
}

@Override
@SuppressWarnings("rawtypes")
public Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
    Class clazz = findLoadedClass(name);

    if (clazz == null) {
        try {
            byte[] bytes = loadClassData(name);
            clazz = defineClass(name, bytes, 0, bytes.length, domain);
            if (resolve) {
                resolveClass(clazz);
            }
        } catch (final Exception e) {
            clazz = super.loadClass(name, resolve);
        }
    }

    return clazz;
}

public byte[] loadClassData(final String name) {
    try {
        final InputStream in = getResourceAsStream(name.replace('.', '/') + ".class");
        final byte[] buffer = new byte[4096];
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        int n;
        while ((n = in.read(buffer, 0, 4096)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    } catch (IOException ex) {
        Logger.getLogger(GameClassLoader.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;

}

@Override
public URL getResource(final String name) {
    try {
        return new URL(base, name);
    } catch (final MalformedURLException e) {
        return null;
    }
}

@Override
public InputStream getResourceAsStream(final String name) {
    try {
        return new URL(base, name).openStream();
    } catch (final IOException e) {
        return null;
    }
}
}
如何调用要加载的类:

  GameClassLoader classLoader = new GameClassLoader(Paths.compiledFolder.toURI().toURL());
            classLoader.loadClass("game", true);

我觉得这对那些知道自己在做什么的人来说是微不足道的

尝试将前导斜杠添加到资源路径中:
final InputStream in=getResourceAsStream(“/”+name.replace(“.”,“/”)+“.class”)


这是我每次调用
getResourceAsStream()
时必须尝试的东西。我刚刚又为你试了一次。这里的路径是相对于用于调用
getResourceAsStream()
的类的包的,因此需要使用前导斜杠来表示“从根开始”。

最后!经过一天半的搜索,瓦肯给我指出了正确的方向: 我将GameClassLoader更改为:

public GameClassLoader(final URL url, ClassLoader parent) {
    super(parent);
最后将基本url添加到getResourceAsStream()中


非常感谢你们的帮助

你不是一个有负担的人。SO上的人不是问问题就是回答问题。太酷了。我很惊讶:你没有包裹吗?我期望classLoader.loadClass(“a.b.c.d.game”,true);我尝试不添加包,只是因为我希望人们能够添加他们自己的小游戏-我知道这违反了惯例,但这样我就可以将所有的小游戏都放在一个文件夹(或Jar)中,它最终会扫描文件夹中的所有文件,检查.class和.Jar文件并加载它们(没有软件包意味着没有扫描子目录)问题是,你的游戏类加载器没有将系统类加载器作为父类加载器来授权给它查找类。(但我还不确定原因;不过还在研究。)谢谢Vulcan!我绞尽脑汁已经一天半了,我想其他人会知道的!我尝试使用URLClassLoader并将父加载程序设置为getSystemClassLoader()没有运气,但老实说,如果我考虑一下,我觉得它根本不会加载资源嗯,也许答案在于将父类加载器写入我的自定义类加载器?不幸的是,这会阻止它加载,问题不是加载类;而是加载类依赖项:java.lang.NoClassDefFoundError:com/mcgm/game/Minigame该课程被认为非常好。很高兴能提供帮助!别忘了将你自己的答案标记为已接受,以供将来其他人参考。
public GameClassLoader(final URL url, ClassLoader parent) {
    super(parent);
final InputStream in = getResourceAsStream(base.getFile() + "/" + name.replace('.', '/') + ".class");