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

Aay*_*sh 1 java javafx spring-data-jpa javafx-8 spring-boot

我有一个 java FX 基本应用程序,它有一个简单的场景(一个表单)。我有一个 Mysql Db,我正在使用 Spring JPA(spring data jpa,即存储库/实体)与之交互。

现在,因为我们知道 javaFx 有一些生命周期钩子,即:init() start() 和 stop()。

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

@Autowired
EmployeeRepo employeeRepo;
Run Code Online (Sandbox Code Playgroud)

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

public void start(Stage primaryStage) throws Exception {

// Some Code

employeeRepo.findAll() <- This is returning null

Run Code Online (Sandbox Code Playgroud)

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

@PostConstruct
public void test() {
// Repo object is not giving null
}
Run Code Online (Sandbox Code Playgroud)

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

请让我知道是否有解决方案,因为我是 JavaFX 的新手

jew*_*sea 7

JavaFX 的依赖注入选项

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

由于您已选择 Spring 作为您的依赖注入框架,并且您希望使用一堆其他 Spring 设施,例如 Spring Data 存储库,您可能希望考虑使用 SpringBoot 应用程序。

您可以使您的 JavaFX 应用程序成为 SpringBoot 应用程序(尽管这并不是为了获得依赖注入而严格必要的),以便在您的应用程序中获得一堆可用的 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

自动连接您的 JavaFX 控制器

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

fxmlLoader.setControllerFactory(springContext::getBean);
Run Code Online (Sandbox Code Playgroud)

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

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

    @Autowired
    public void mySpringService;

    public void initialize() {
        usernameLabel.setText(
            mySpringService.getLoggedInUsername()
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

自动连接 JavaFX 应用程序类

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

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

springContext
    .getAutowireCapableBeanFactory()
    .autowireBeanProperties(
        this,
        AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, 
        true
    );
Run Code Online (Sandbox Code Playgroud)

mvvmFX框架采用了类似的方法除了以上概述,以SpringBoot使用JavaFX应用程序集成:

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

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

SpringApplication.run(
    DemoApplication.class, 
    getParameters().getRaw().toArray(new String[0])
);
Run Code Online (Sandbox Code Playgroud)

其他事宜

如果需要,对 SpringApplication 的启动进行更多控制,您可以使用 SpringApplicationBuilder 例如:

ConfigurableApplicationContext startupContext =
        new SpringApplicationBuilder(DemoApplication.class)
                .web(WebApplicationType.NONE)
                .run(args);
Run Code Online (Sandbox Code Playgroud)

这个答案只是为您提供有关如何解决这个问题的提示,而不是作为关于如何将依赖注入与 JavaFX 集成的通用指南,这可能最终成为一个非常棘手的主题,需要全面覆盖。