【问题标题】:Adding Spring Dependency Injection in JavaFX (JPA Repo, Service)在 JavaFX (JPA Repo, Service) 中添加 Spring 依赖注入
【发布时间】:2023-03-03 09:32:20
【问题描述】:

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

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

假设我想使用 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 新手,请告诉我是否有解决方案

【问题讨论】:

    标签: java spring-boot javafx spring-data-jpa javafx-8


    【解决方案1】:

    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 依赖项中将您的类注释为 Spring @Component@Autowired。通过这种方式,FXMLLoader 将基于 @FXML 的引用注入到您的 UI 元素,它还将委托给 spring 上下文以注入 Spring 依赖项。

    @Component
    public class DemoController {
        @FXML
        private Label usernameLabel; 
    
        @Autowired
        public void mySpringService;
    
        public void initialize() {
            usernameLabel.setText(
                mySpringService.getLoggedInUsername()
            );
        }
    }
    

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

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

    您可能需要注意的一件事是,在运行 SpringBoot 应用程序时,会生成一个新的应用程序实例,并且您已经拥有一个由 JavaFX 系统启动的 JavaFX 应用程序实例,因此如果出现以下情况,这将导致两个 JavaFX 应用程序实例SpringBoot 应用程序和 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

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

    【讨论】:

      猜你喜欢
      • 2012-08-22
      • 2017-03-25
      • 1970-01-01
      • 2017-04-07
      • 1970-01-01
      • 2015-10-04
      • 1970-01-01
      • 2023-03-13
      相关资源
      最近更新 更多