使用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。若要使用该方案,需按以下步骤操作:
- 创建工厂接口:
public interface ScreenServiceFactory { ScreenService create(Stage primaryStage); }
- 修改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(); } }
- 在模块中安装工厂:
public class ServiceModule extends AbstractModule { @Override protected void configure() { install(new FactoryModuleBuilder() .implement(ScreenService.class, ScreenService.class) .build(ScreenServiceFactory.class)); } // ... 其他Provider代码 ... }
- 在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
相关产品推荐
相关产品推荐

