JavaFX 应用程序中的 Spring 应用程序上下文

标签 spring javafx dependency-injection autowired applicationcontext

我有兴趣在 JavaFX 应用程序中使用 ApplicationContext。我问自己是否有更智能的方法来将 ApplicationContext 作为 Application 子类本身的属性进行处理。

@Configuration
@ComponentScan("...")
public class Gui extends Application {

   private AnnotationConfigApplicationContext context;

   public static void main(String[] args) {
     launch(args);
   }

   /* (non-Javadoc)
    * @see javafx.application.Application#start(javafx.stage.Stage)
    */

    @Override
    public void start(Stage stage) throws Exception {       
      context = new AnnotationConfigApplicationContext(Gui.class);
      //...         
    }       
}

我的目的是将ApplicationContextGui.class分开,并进一步使用@Autowired注释在Spring组件中注入(inject)Gui.class.

最佳答案

首先,将应用程序配置与 Application 子类分开。 JavaFX 将为您创建一个 Application 子类的实例,并且该类应该只有一个实例。 Spring 将创建任何配置类的实例,因此,即使您无权访问它们,您最终也会获得 Application 类的多个实例,这不是预期的用途。

至于您正在寻找的分离,我认为您想要的是将 ApplicationContext 的创建和交互与构建和配置 UI 的工作分开,并使其与应用程序的业务层等。但是,我认为您正在以应有的方式向后看待这个问题。 Application 类,特别是其 start() 方法,是 JavaFX 应用程序的入口点。 FX 框架在启动时执行一些内务处理(启动 FX 工具包等),创建该类的实例,并调用 start 方法。由于这是您进行应用程序的基本组装的地方,因此它是创建 ApplicationContext 并从中获取一两个 bean 的自然且正确的位置。如果您想将其与 UI 的创建和配置分开,则应将 UI 的创建和配置移至其他地方。 Application 类的唯一职责应该是启动应用程序:这样就根本没有状态可以注入(inject)到该类中。

使用这种方法,一个最小的 Spring 驱动的 FX 应用程序可能如下所示:

AppConfig.java:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class AppConfig {

    @Bean
    public Service service() {
        return new Service();
    }

    @Bean
    @Scope("prototype")
    public Gui gui() {
        return new Gui();
    }
}

服务.java:

public class Service {

    public String confirmationMessage() {
        return "You have been confirmed";
    }
}

Gui.java(请注意,这现在不是 Application 子类,但它几乎完成了所有 GUI 工作):

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;

public class Gui {

    @Inject
    private Service service ;

    private VBox view ;
    private Label label ;

    public Gui() {
        Button button = new Button("Press for confirmation");
        label = new Label();
        label.setVisible(false);
        button.setOnAction(e -> label.setVisible(true));

        view = new VBox(5, label, button);
        view.setPadding(new Insets(20));
        view.setAlignment(Pos.CENTER);
    }

    @PostConstruct
    private void init() {
        label.setText(service.confirmationMessage());
    }

    public Parent getView() {
        return view ;
    }
}

最后是Application 类Main.java。请注意,这实际上并没有执行任何 GUI 工作:它只是管理应用程序生命周期:创建 ApplicationContext,从中获取代表主视图的 bean,并在主阶段中显示它。所有实际的 GUI 工作都委托(delegate)给 MainView 类,该类的实例由 Spring 管理。

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    private AbstractApplicationContext context ;

    @Override
    public void start(Stage primaryStage) {
        context = new AnnotationConfigApplicationContext(AppConfig.class);
        Parent mainView = context.getBean(Gui.class).getView();
        primaryStage.setScene( new Scene(mainView) );
        primaryStage.show();
    }

    @Override
    public void stop() {
        context.close();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

您可以扩展此方法,以便它在表示层使用完整的 MVC/MVP 设计,如果需要,可以使用 FXML 等。

关于JavaFX 应用程序中的 Spring 应用程序上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39377920/

相关文章:

java - 有没有办法使用 Spring Boot、Liquibase 和 sql-script 进行集成测试?

java - Spring 集成: Failed to send message to channel 'executionFilterChannel' within timeout: -1

java - 如何删除具有相同对象名称的JavaFx标签

Javafx Choicebox - 如何检查是否选择/激活

java - Guice:一个 "Provider<T>"用于多个实现

java - 使用相同 onMessage 的多个 MessageListener 的线程安全性?

java - 在 Spring 请求处理程序中处理请求中传入的空值

JavaFX UI 在事件监听器的 JavaFX 应用程序线程中卡住,但可与 Platform.runLater 一起使用

c# - asp.net 核心构造函数注入(inject)继承

java - 从另一个 jar 添加到 spring 接口(interface)实现