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

a64a0gku  于 2023-02-18  发布在  Java
关注(0)|答案(1)|浏览(283)

我有一个Java FX基本应用程序,它有一个简单的场景(一个表单)。我有一个Mysql DB,我正在使用Spring JPA(Spring Data JPA,即存储库/实体)与之交互。
现在,既然我们知道javaFx有一些生命周期钩子,即:init()启动()和停止()。
假设我想使用JPA**保存()**方法在数据库中插入数据。通常,如果它是我的控制器,那么一个普通的DB注入就像:

@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新手

h5qlskok

h5qlskok1#

JavaFX的依赖关系注入选项

有很多方法可以将依赖注入到JavaFX应用程序中,例如Gluon有一个名为Gluon Ignite的项目,它使JavaFX应用程序能够支持各种依赖注入框架,如Guice、Spring和Dagger。
由于您已经选择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);
    }
}

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

自动连接JavaFX控制器

要使JAVAFX FXML控制器自动连线,除了在FXMLLoader上执行以下调用之外:

fxmlLoader.setControllerFactory(springContext::getBean);

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

@Component
@Scope("prototype")
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服务端点控制器。
在控制器上使用@Scope("prototype"),因为我们希望获得一个新的控制器来支持每次加载FXML时创建的新视图对象,而不是重用现有的控制器,该控制器与一组不同的视图对象相关。

分离Sping 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
    );

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

要将参数从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集成的通用指南,这可能最终成为一个相当棘手的主题,无法全面涵盖。

相关问题