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

使用Guice注入JavaFX ScreenService单例时遇NPE问题求助

问题分析与修复方案

核心问题原因

你在Main.java中调用injector.getInstance(ScreenService.class)时,没有使用@Screens限定符,而Guice会为无限定符的ScreenService类型自动创建新实例(你的模块仅绑定了带@Screens限定符的单例)。这导致:

  • 手动调用launch(primaryStage)的是无限定符的实例
  • LoginController中注入的是带@Screens限定符的单例实例
    两个实例完全独立,后者的stage字段始终为null,调用loadScene时自然抛出NullPointerException。

修复步骤

1. 修改Main.java获取正确的单例实例

在获取ScreenService时加上限定符,确保拿到模块中配置的单例:

@Override
public void start(Stage primaryStage) {
    Injector injector = Guice.createInjector(new ServiceModule());
    // 使用@Screens限定符获取单例实例
    ScreenService screenService = injector.getInstance(Key.get(ScreenService.class, ServiceModule.Screens.class));
    screenService.launch(primaryStage);
}

2. 可选:优化Stage的注入方式(避免手动调用launch)

如果想彻底去掉手动调用launch的步骤,可以通过Guice绑定直接注入primaryStage:

  • 首先在模块中绑定Stage为单例并初始化ScreenService:
public class ServiceModule extends AbstractModule {
    // ... 原有限定符和Provider代码 ...

    @Provides
    @Singleton
    Stage providePrimaryStage() {
        return new Stage();
    }

    @Provides
    @Singleton
    @Screens
    static ScreenService provideScreenService(Injector injector, Stage stage) {
        ScreenService service = new ScreenService(injector);
        service.launch(stage); // 直接在Provider中完成初始化
        return service;
    }
}
  • 然后Main.java简化为:
@Override
public void start(Stage primaryStage) {
    Injector injector = Guice.createInjector(new ServiceModule());
    // ScreenService已自动初始化完成,无需额外调用
}

AssistedInject方案失败的补充说明

你尝试的AssistedInject方案失败,大概率是因为未正确配置工厂类或未在模块中安装FactoryModuleBuilder。若要使用该方案,需按以下步骤操作:

  1. 创建工厂接口:
public interface ScreenServiceFactory {
    ScreenService create(Stage primaryStage);
}
  1. 修改ScreenService构造方法:
public class ScreenService {
    private final Stage stage;
    private final Injector injector;

    @Inject
    public ScreenService(Injector injector, @Assisted Stage stage) {
        this.injector = injector;
        this.stage = stage;
        this.stage.setTitle("Brokerage Application");
        loadScene("/login-view.fxml");
        this.stage.show();
    }
}
  1. 在模块中安装工厂:
public class ServiceModule extends AbstractModule {
    @Override
    protected void configure() {
        install(new FactoryModuleBuilder()
                .implement(ScreenService.class, ScreenService.class)
                .build(ScreenServiceFactory.class));
    }

    // ... 其他Provider代码 ...
}
  1. 在Main中使用工厂创建实例:
@Override
public void start(Stage primaryStage) {
    Injector injector = Guice.createInjector(new ServiceModule());
    ScreenServiceFactory factory = injector.getInstance(ScreenServiceFactory.class);
    ScreenService screenService = factory.create(primaryStage);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 23:03:10