在 JavaFX 中添加 Spring 依赖注入(JPA Repo、服务)

Adding Spring Dependency Injection in JavaFX (JPA Repo, Service)

我有一个 java FX 基本应用程序,它有一个简单的场景(一种形式)。 我有一个 Mysql Db,我正在使用 Spring JPA(spring 数据 jpa,即 repository/entities)与之交互。

现在,因为我们知道 javaFx 有一些生命周期钩子,即: 在里面() 开始()和停止()。

假设我想使用 JPA save() 方法在数据库中插入数据。通常,如果是我的控制器,正常的数据库注入如:

@Autowired
EmployeeRepo employeeRepo;

本来可以的。但是,我无法在生命周期方法中访问它(或任何自动注入)。

public void start(Stage primaryStage) throws Exception {

// Some Code

employeeRepo.findAll() <- This is returning null

但是,当我添加一个测试方法并使用它时,它工作正常:

@PostConstruct
public void test() {
// Repo object is not giving null
}

有没有一种方法可以在我的按钮侦听器中手动注入依赖项或将其传递给启动方法。

如果有解决方案请告诉我,因为我是 JavaFX 的新手

JavaFX 的依赖注入选项

有很多方法可以将依赖注入到 JavaFX 应用程序中。例如 Gluon 有一个名为 Gluon Ignite 的项目,它为各种依赖注入框架启用 JavaFX 应用程序,例如 Guice、Spring 和 Dagger。

由于您已选择 Spring 作为您的依赖注入框架,并且您希望使用一系列其他 Spring 设施,例如 Spring 数据存储库,您不妨考虑使用Spring启动应用程序。

您可以使您的 JavaFX 应用程序成为 Spring 启动应用程序(尽管这并不是获得依赖项注入所必需的)以便在您的应用程序中获得大量可用的 Spring 功能.搜索一下网上有一些教程。

Spring 和 JavaFX

的基本示例集成

以下是将 JavaFX 与 SpringBoot 应用程序集成的教程示例:

该示例的关键部分是应用程序的 init() 方法(我刚刚复制并粘贴并复制到此处以供参考):

@SpringBootApplication
public class DemoApplication extends Application {

    private ConfigurableApplicationContext springContext;
    private Parent root;

    @Override
    public void init() throws Exception {
        springContext = SpringApplication.run(DemoApplication.class);
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/sample.fxml"));
        fxmlLoader.setControllerFactory(springContext::getBean);
        root = fxmlLoader.load();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setTitle("Hello World");
        Scene scene = new Scene(root, 800, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    @Override
    public void stop() throws Exception {
        springContext.stop();
    }


    public static void main(String[] args) {
        launch(DemoApplication.class, args);
    }
}

示例应用程序是 运行 SpringBoot 应用程序,用于启动 Spring 系统并让它在 init 方法中提供应用程序上下文。然后应用程序使用 FXMLLoader setControllerFactory() 方法允许 Spring 实例化 FXML 控制器并在应用程序中注入对 Spring bean 的引用。

自动连接您的 JavaFX 控制器

要让您的 JAVAFX FXML 控制器自动装配,除了调用 FXMLLoader 之外:

fxmlLoader.setControllerFactory(springContext::getBean);

您还需要将 class 注释为 Spring @Component,并在您希望控制器使用的任何 Spring 依赖项中注释 @Autowired。通过这种方式,FXMLLoader 将向您的 UI 元素注入基于 @FXML 的引用,它还将委托给 spring 上下文以注入 Spring 依赖项。

@Component
public class DemoController {
    @FXML
    private Label usernameLabel; 

    @Autowired
    public SpringService mySpringService;

    public void initialize() {
        usernameLabel.setText(
            mySpringService.getLoggedInUsername()
        );
    }
}

注意,Spring 有一个 @Controller 注释,可以用来注释 JavaFX 控制器而不是 @Component 注释,但我建议避免使用 @Controller 用于此目的,而是 @Controller 用于 Spring REST 服务端点控制器定义的注释。

Spring 引导应用程序和 JavaFX 应用程序之间的关注点分离

您可能需要注意的一件事是 运行 SpringBoot 应用程序会生成一个新的应用程序实例,并且您已经有一个由 JavaFX 系统启动的 JavaFX 应用程序实例,因此如果 SpringBoot 应用程序和 JavaFX 应用程序基于相同的 class(如上所示),这将导致两个 JavaFX 应用程序实例,这可能会造成混淆。

因此,最好将 Spring 应用程序和 JavaFX 应用程序分开。这增强了应用程序的 UI 和服务部分之间的关​​注点分离,并使测试更容易,因为 Spring 应用程序可以独立于启动和关闭 JavaFX 应用程序进行单元测试。

自动连接 JavaFX 应用程序class

请注意,使用上述设置,它不会自动装配 JavaFX 应用程序 class 实例化实例。如果您希望这样做,您可以使用下面说明的技术在 JavaFX 实例化应用程序中注入 bean class:

  • Injecting beans into a class outside the Spring managed context

将以下代码放入应用程序的 init 方法中:

springContext
    .getAutowireCapableBeanFactory()
    .autowireBeanProperties(
        this,
        AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, 
        true
    );

mvvmFX framework 使用与上述类似的方法将 SpringBoot 与 JavaFX 应用程序集成:

将命令行参数从 JavaFX 传递到 SpringBoot

要将参数从 JavaFX 应用程序传递到 SpringBoot 应用程序,请使用:

SpringApplication.run(
    DemoApplication.class, 
    getParameters().getRaw().toArray(new String[0])
);

其他问题

如果需要,甚至可以更好地控制 SpringApplication 的启动,您可以使用 SpringApplicationBuilder,例如:

ConfigurableApplicationContext startupContext =
        new SpringApplicationBuilder(DemoApplication.class)
                .web(WebApplicationType.NONE)
                .run(args);

这个答案只是为了给你一些提示,告诉你如何解决这个问题,而不是作为一个关于如何将依赖注入与 JavaFX 集成的通用指南,这可能最终成为一个非常棘手的主题,无法全面涵盖。