注入Java fx应用程序的依赖项

时间:2015-01-28 08:44:37

标签: javafx javafx-8

我可能会错过一些解决方法,但我还想找到一个解决方案,我可以将依赖关系,例如我的事件总线实例和一些服务接口传递给我的javafx应用程序。

我有一个UI-Init类,它只是启动应用程序并接收UI的一些依赖项,如eventBus:

public class Frontend {

public Frontend(MBassador<EventBase> eventBus) {
    Application.launch(AppGui.class);
}

我的AppGui类扩展了Application并加载了FXML:

public class AppGui extends Application {

private Stage primaryStage;
private GridPane rootLayout;

@Override
public void start(Stage primaryStage) {
    this.primaryStage = primaryStage;
    try {
        // Load root layout from fxml file.
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("RootLayout.fxml"));
        rootLayout = (GridPane) loader.load();

        // Show the scene containing the root layout.
        Scene scene = new Scene(rootLayout);
        scene.setFill(null);
        primaryStage.setScene(scene);

        RootLayoutController rootController = loader.getController();
        rootController.init(/*here I would like to inject my eventBus*/);

        primaryStage.show();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

现在,我如何将eventBus和其他服务接口传递给此控制器?我已经读过使用像guice(How can JavaFX controllers access other services?)或者afterburner.fx这样的DI框架来使用它。但即使我在我的应用程序的其余部分使用guice,我还需要将Injector实例传递给JavaFX应用程序?。

但是Application.launch(AppGui.class);是静态的,并在javafx线程上内部创建一个AppGui实例,我无法访问该实例。那么如何在不使用静态变量的情况下将依赖项注入AppGui对象呢?

2 个答案:

答案 0 :(得分:2)

以下是我的工作:

Application类有几个生命周期回调,init()stop()

来自Javadocs:

  

public void init() throws java.lang.Exception

     

应用程序初始化方法。在加载和构造Application类之后立即调用此方法。应用程序可以覆盖此方法以在实际启动应用程序之前执行初始化。

     

public void stop() throws java.lang.Exception

     

当应用程序停止时调用此方法,并为准备应用程序退出和销毁资源提供方便的位置。

同样来自Javadocs,生命周期:

  
      
  1. 构造指定的Application
  2. 的实例   
  3. 调用init()方法
  4.   
  5. 调用start(javafx.stage.Stage)方法
  6.   
  7. 等待应用程序完成,当发生以下任一情况时会发生:   
        
    • 应用程序调用{​​{1}}
    •   
    • 最后一个窗口已关闭且Platform.exit()上的implicitExit属性为Platform
    •   
  8.   
  9. 调用stop()方法
  10.   

我在true中启动IoC容器并在init()中将其停止。现在,我的stop()类具有对IoC容器的引用,并且可以为第一个控制器提供其依赖项。

事实上,我让IoC框架管理控制器。我使用Application将它们设置为加载的FXML,而不是使用FXMLLoader.setController()指定它们。

答案 1 :(得分:0)

在调用launch()之前,您可以将静态引用传递给应用程序类。类似的东西:

public class Frontend {
    public Frontend(MBassador<EventBase> eventBus) {
        AppGui.setEventBus(eventBus);
        Application.launch(AppGui.class);
    }
}

public class AppGui extends Application {
    private static MBassador<EventBase> eventBus;
    public static void setEventBus(MBassador<EventBase> eventBus) {
        this.eventBus = eventBus;
    }

    private MBassador<EventBase> eventBus;

    @Override
    public void init() {
        if (AppGui.eventBus == null) {
            throw new IllegalStateException(); 
            // or however you want to handle that state
        } else {
            this.eventBus = AppGui.eventBus;
            AppGui.eventBus = null; 
        }
    }
}

您是否保留并使用静态引用,或者将静态引用复制到本地引用取决于您和应用程序的设计。如果您希望实例化多个AppGui副本,则可能需要本地引用。

不知道这是否是线程安全的(可能不是)。来自@Nikos和@James_D的建议是坚实的,首选......但有时你只需要一个黑客。 :) YMMV