You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Spigot插件开发问题:三个类无法协同工作引发命令执行异常

解决Spigot插件中的"Plugin already initialized!"错误

我正在开发一款Spigot插件,包含三个核心类:GUI、OpenGui和BanGUIMain,调用注册的/opengui命令时触发了Plugin already initialized!错误,相关代码和错误日志如下:

现有代码

GUI类

public class GUI {
  private BanGUIMain main = new BanGUIMain(); /*line 16*/
  public void createOptionsGUI(Player p) {}
}

OpenGui类

public class OpenGui implements CommandExecutor {
  @Override
  public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
    if (sender instanceof Player) {
      if (sender.hasPermission("bangui.opengui")) {
        GUI gui = new GUI(); /*line 14*/
        gui.createOptionsGUI((Player) sender);
      }
    }
    return false;
  }
}

BanGUIMain类

public final class BanGUIMain extends JavaPlugin { /*this is line 12*/
  // 无关代码省略
}

触发的错误日志

[16:29:55 ERROR]: null
org.bukkit.command.CommandException: Unhandled exception executing command 'opengui' in plugin BanGUIMain v1.0.0
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:46) ~[server.jar:git-Spigot-db6de12-18fbb24]
at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:141) ~[server.jar:git-Spigot-db6de12-18fbb24]
at org.bukkit.craftbukkit.v1_8_R3.CraftServer.dispatchCommand(CraftServer.java:641) ~[server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.PlayerConnection.handleCommand(PlayerConnection.java:1162) [server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.PlayerConnection.a(PlayerConnection.java:997) [server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.PacketPlayInChat.a(PacketPlayInChat.java:45) [server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.PacketPlayInChat.a(PacketPlayInChat.java:1) [server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.PlayerConnectionUtils$1.run(SourceFile:13) [server.jar:git-Spigot-db6de12-18fbb24]
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [?:1.8.0_271]
at java.util.concurrent.FutureTask.run(Unknown Source) [?:1.8.0_271]
at net.minecraft.server.v1_8_R3.SystemUtils.a(SourceFile:44) [server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:715) [server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:374) [server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:654) [server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:557) [server.jar:git-Spigot-db6de12-18fbb24]
at java.lang.Thread.run(Unknown Source) [?:1.8.0_271]
Caused by: java.lang.IllegalArgumentException: Plugin already initialized!
at org.bukkit.plugin.java.PluginClassLoader.initialize(PluginClassLoader.java:122) ~[server.jar:git-Spigot-db6de12-18fbb24]
at org.bukkit.plugin.java.JavaPlugin.<init>(JavaPlugin.java:66) ~[server.jar:git-Spigot-db6de12-18fbb24]
at me.roughlyunderscore.plugins.premium.bangui.main.BanGUIMain.<init>(BanGUIMain.java:12) ~[?:?]
at me.roughlyunderscore.plugins.premium.bangui.main.gui.GUI.<init>(GUI.java:16) ~[?:?]
at me.roughlyunderscore.plugins.premium.bangui.main.commands.OpenGui.onCommand(OpenGui.java:14) ~[?:?]
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44) ~[server.jar:git-Spigot-db6de12-18fbb24]
... 15 more
Caused by: java.lang.IllegalStateException: Initial initialization
at org.bukkit.plugin.java.PluginClassLoader.initialize(PluginClassLoader.java:125) ~[server.jar:git-Spigot-db6de12-18fbb24]
at org.bukkit.plugin.java.JavaPlugin.<init>(JavaPlugin.java:66) ~[server.jar:git-Spigot-db6de12-18fbb24]
at me.roughlyunderscore.plugins.premium.bangui.main.BanGUIMain.<init>(BanGUIMain.java:12) ~[?:?]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:1.8.0_271]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) ~[?:1.8.0_271]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) ~[?:1.8.0_271]
at java.lang.reflect.Constructor.newInstance(Unknown Source) ~[?:1.8.0_271]
at java.lang.Class.newInstance(Unknown Source) ~[?:1.8.0_271]
at org.bukkit.plugin.java.PluginClassLoader.<init>(PluginClassLoader.java:76) ~[server.jar:git-Spigot-db6de12-18fbb24]
at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.java:131) ~[server.jar:git-Spigot-db6de12-18fbb24]
at org.bukkit.plugin.SimplePluginManager.loadPlugin(SimplePluginManager.java:329) ~[server.jar:git-Spigot-db6de12-18fbb24]
at org.bukkit.plugin.SimplePluginManager.loadPlugins(SimplePluginManager.java:251) ~[server.jar:git-Spigot-db6de12-18fbb24]
at org.bukkit.craftbukkit.v1_8_R3.CraftServer.loadPlugins(CraftServer.java:292) ~[server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.DedicatedServer.init(DedicatedServer.java:198) ~[server.jar:git-Spigot-db6de12-18fbb24]
at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:525) ~[server.jar:git-Spigot-db6de12-18fbb24]
... 1 more

错误原因分析

你的推测方向没错,但核心问题不是循环实例化或者需要销毁对象,而是Spigot插件的主类(继承JavaPlugin的类)是单例模式——只能由Spigot服务器在加载插件时初始化一次。

当你在GUI类里手动new BanGUIMain()时,相当于尝试创建第二个插件实例,而Spigot绝对不允许一个插件同时存在多个实例,所以直接抛出了Plugin already initialized!异常。

简单说:你永远不要自己去new主类对象,主类的实例是服务器帮你创建好的,其他类只需要用这个现成的实例就行。


解决方法:依赖注入(传递主类实例)

我们需要把服务器已经创建好的BanGUIMain实例传递给OpenGui和GUI类,而不是让它们自己去新建主类对象。具体步骤如下:

1. 修改主类BanGUIMain,传递自身实例给命令类

在主类的onEnable()方法中注册命令时,把主类的this(当前实例)传给OpenGui:

public final class BanGUIMain extends JavaPlugin {
  @Override
  public void onEnable() {
    // 注册/opengui命令,将主类实例传递给OpenGui
    this.getCommand("opengui").setExecutor(new OpenGui(this));
  }
}

2. 修改OpenGui类,接收主类实例并传递给GUI

让OpenGui持有主类实例,创建GUI对象时把这个实例传进去:

public class OpenGui implements CommandExecutor {
  private final BanGUIMain main;

  // 构造方法接收主类实例
  public OpenGui(BanGUIMain main) {
    this.main = main;
  }

  @Override
  public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
    if (sender instanceof Player) {
      Player player = (Player) sender;
      if (player.hasPermission("bangui.opengui")) {
        // 创建GUI时传递主类实例
        GUI gui = new GUI(main);
        gui.createOptionsGUI(player);
      }
    }
    return true; // 建议返回true表示命令执行成功(可根据需求调整)
  }
}

3. 修改GUI类,接收主类实例

去掉new BanGUIMain()的代码,改为通过构造方法接收主类实例:

public class GUI {
  private final BanGUIMain main;

  // 构造方法接收主类实例
  public GUI(BanGUIMain main) {
    this.main = main;
  }

  public void createOptionsGUI(Player p) {
    // 在这里可以正常使用main实例,比如调用main.getConfig()获取配置、main.getServer()获取服务器对象等
  }
}

额外说明

  • 不需要手动销毁GUI实例:Java的垃圾回收机制会自动处理不再被引用的对象,你完全不用手动管理销毁逻辑。
  • 用final修饰主类实例是好习惯:可以确保这个实例不会被意外修改,避免潜在的bug。
  • 这种传递实例的方式叫依赖注入,是Spigot插件开发的标准做法,后续你的监听器、其他命令类如果需要用主类实例,都可以用同样的方式传递。

内容的提问来源于stack exchange,提问作者LeopardL GD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 16:32:39