当前位置: 首页 > 知识库问答 >
问题:

具有自定义界面的Java插件

晋涛
2023-03-14

像spigot/bukkit插件一样,我希望能够在文件中加载JAR并加载它们的类。我用java类加载器成功地实现了这一点,但该类必须扩展runnable才能工作。我想为每个插件(jar)实现自己的自定义接口。所以我可以在插件加载时运行函数等等。如果有人知道怎么做,请告诉我。

共有1个答案

尉迟正平
2023-03-14

插件是一个. jar文件。插件有一个plugin.properties文件,其中包含插件的属性。

看起来是这样的:

plugin.main=com.example.plugins.ExamplePlugin
plugin.name=Example Plugin
plugin.description=Test 123
plugin.version=1.0

该文件包含主类、插件名称、描述和版本。

插件必须具有从抽象插件类继承的类。这算是主要课程。

让我们从Plugin-类开始:

package com.example.plugins;

public abstract class Plugin {
    
    protected PluginProperty property;
    
    public abstract void onEnable();
    public abstract void onDisable();

    public PluginProperty getProperty() {
        return property;
    }
    public void setProperty(PluginProperty property) {
        this.property = property;
    }
}

如你所见,我在这里选择了一个抽象类。

该类由两个抽象方法组成(onEnableonDisable)。该插件还有一个PluginProperty对象。这个类在spiget中的等价物是JavaPlugin

让我们看看PluginProperty类。

package com.example.plugins;

public class PluginProperty {
    
    private String main;
    
    private String name;
    private String description;
    private double version;
    
    public PluginProperty(String main, String name, String description, double version) {
        this.main = main;
        
        this.name = name;
        this.description = description;
        this.version = version;
    }

    public String getMain() {
        return main;
    }

    public void setMain(String main) {
        this.main = main;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public double getVersion() {
        return version;
    }

    public void setVersion(double version) {
        this.version = version;
    }
}

这个类具有插件的所有必要属性。这里的大部分内容都是不言自明的,但我仍然想讨论main

该字符串包含插件的主插件类的名称。这与插件中的main基本相同。yml在插口中。

这是PluginLoader-class:

package com.example.plugins;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Properties;
import java.util.zip.ZipException;

public class PluginLoader {
    
    private static PluginProperty loadPluginProperties(File file) throws ZipException, IOException {
        URL url = file.toURI().toURL();
        String jarURL = "jar:" + url +"!/plugin.properties";
        
        InputStream input;
        URL inputURL = new URL(jarURL);
        JarURLConnection conn = (JarURLConnection)inputURL.openConnection();
        input = conn.getInputStream();
        
        Properties property = new Properties();
        
        property.load(input);
        
        String main = property.getProperty("plugin.main");
        
        String name = property.getProperty("plugin.name");
        String description = property.getProperty("description");
        double version = Double.parseDouble(property.getProperty("plugin.version"));
        
        
        return new PluginProperty(main, name, description, version);
    }
    
    public static Plugin loadPlugin(File file) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
        if(!file.exists()) {
            return null;
        }
        
        PluginProperty property = loadPluginProperties(file);
        
        URL url = file.toURI().toURL();
        String jarURL = "jar:" + url + "!/";
        URL urls[] = {new URL(jarURL)};
        URLClassLoader ucl = new URLClassLoader(urls);
        Plugin plugin = (Plugin) Class.forName(property.getMain(), true, ucl).getDeclaredConstructor().newInstance();
        plugin.setProperty(property);
        
        return plugin;
    }
}

privateloadPluginProperties方法加载插件属性并返回所需的对象。loadPlugin方法将属性中指定的主类加载到一个对象中并返回它。

我刚刚给了你插件系统的基本框架。但是你应该如何使用它呢?让我们从一个示例加载器开始。

以下是-类:

package com.example.plugins;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

public class Main {
    
    public static List<Plugin> plugins = new ArrayList<Plugin>();

    public static void main(String[] args) {
        File[] pluginFiles = new File("plugins").listFiles();
        
        //Load plugins
        for(File f : pluginFiles) {
            if(f.isDirectory()) {
                continue;
            }
            
            if(!f.getName().endsWith(".jar")) {
                continue;
            }
            
            Plugin p = null;
            
            try {
                p = PluginLoader.loadPlugin(f);
            } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | IOException e) {
                System.err.println("Failed to load plugin!");
                
                e.printStackTrace();
            }
            
            Main.plugins.add(p);
        }
        
        //Enable plugins
        for(Plugin p : plugins) {
            p.onEnable();
        }
        
        //Disable plugins
        for(Plugin p : plugins) {
            p.onDisable();
        }
    }

}

我不想在这里详述太多细节,因为我认为这是不言自明的。如果你有问题,就通过评论问我。

导出之前作为JAR编写的文件后,将其添加到新项目的类路径中。别忘了创建一个插件。属性文件。

这是一个与兼容的示例插件。属性上面指定的文件:

package com.example.plugins;

public class ExamplePlugin extends Plugin {

    @Override
    public void onEnable() {
        System.out.println("Hello world!");
    }
    
    @Override
    public void onDisable() {
        
    }
}

当我导出这个插件并将其放入plugins文件夹时,我得到以下输出:Hello world

建议使用JSON或YAML、XML等,而不是内置的Java属性文件。这是插件的基本结构。玩得开心!

 类似资料:
  • 一份简单的元素定义 Editor.UI.registerElement('foobar-label', { template: ` <div class="text">Foobar</div> `, style: ` .text { color: black; padding: 2px 5px; border-radius: 3px

  • 但为了让它看起来像这样,我必须添加硬编码的大小限制,从而使它不具有自适应性。 这里是xml布局。 如何使此图像具有自适应性,并且仍然看起来像第一张图像?

  • 问题内容: 这是我的http服务器: 我需要在myHander内部访问实例t1。 有什么办法吗? 谢谢! 问题答案: 有一种方法可以将属性设置为class: 您必须注意,在所有使用myHandler的地方都将是t1的相同实例

  • 我想按字母顺序对字段名列表进行排序,但是我需要在比较器的doCompare方法中包含一个条件,以便如果字段名是“pk”,则始终将其排序到列表的顶部。我所拥有的内容如下,但我不确定我是否采取了正确的方法,特别是reurn值为-1000。对此的任何建议都将不胜感激。

  • 我们在中基于BaseTreeVisitor实现了一个自定义规则https://github.com/SonarSource/sonar-java/tree/master/java-checks/src/main/java/org/sonar/java/checks如中所述http://docs.sonarqube.org/display/SONAR/Extending编码规则。我们能够部署它,它看

  • 我为SonarQube创建了一个分析F#代码的自定义插件。这个插件的功能如预期,其结果可以在SonarQube UI中看到。 我现在正试图通过将一个解决方案绑定到我的SonarQube实例中包含的解决方案,将SonarLint与Visual Studio一起使用。但是,在Visual Studio中通过SonarLint分析代码时,不会使用F#规则。 在Visual Studio中让这个自定义的F