簡體   English   中英

使用依賴注入配置 JavaFX

[英]Configuring JavaFX using Dependency Injection

我有一個要配置的應用程序(設置數據庫,初始化工作池),然后啟動我的 JavaFX 應用程序並注入配置。不幸的是,Java 的每個 DI 框架都希望能夠構造注入的對象,但是運行 JavaFX 應用程序的唯一方法是使用Application.launch啟動它。

我能夠想出的唯一解決方案是在我的應用程序構造函數中啟動我的 DI 框架,但這使得無法在應用程序啟動之前配置 DI 或在應用程序退出時清理。

Application.launch()將啟動 JavaFX 運行時、JavaFX 應用程序線程,並且如問題中所述,將創建Application子類的實例。 然后它在該Application實例上調用生命周期方法。

大多數示例僅使用Application.start()方法,該方法在 JavaFX 應用程序線程上執行,但還有其他生命周期方法(默認為無操作)也被執行。 init()方法在start()之前執行。 它在主線程上執行,但保證在start()被調用之前完成。 FX 應用程序退出時調用stop()方法。 這些方法都在與start()方法相同的Application實例上調用。


一種解決方案是利用這些生命周期方法來啟動、配置和清理依賴注入框架。 所以這里我們本質上是使用 JavaFX 生命周期,並掛鈎到它來手動控制 DI 框架生命周期。 這是 Spring 引導的示例:

package org.jamesd.examples.springfx;

import java.io.IOException;
import java.util.List;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

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

@SpringBootApplication
public class App extends Application {

    private ConfigurableApplicationContext context ;

    @Override
    public void init() {
        List<String> rawParams = getParameters().getRaw() ;
        String[] args = rawParams.toArray(new String[rawParams.size()]) ;
        context = SpringApplication.run(getClass(), args);
        // further configuration on context as needed
    }


    @Override
    public void start(Stage stage) throws IOException {

        FXMLLoader loader = new FXMLLoader(getClass().getResource("Main.fxml"));
        loader.setControllerFactory(context::getBean);
        Parent root = loader.load();
        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

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


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

}

另一種方法是繞過標准的 JavaFX 啟動過程。 JavaFX 9 和更高版本具有Platform.startup()方法,該方法“手動”啟動 JavaFX 運行時,啟動 FX 應用程序線程,並在該線程上調用提供的Runnable 通過繞過通常的 JavaFX 啟動過程,您可以使用 DI 框架的啟動過程,並在該過程中的適當位置根據需要調用Platform.startup() 這在某種意義上是與前一種相反的方法:我們使用 DI 框架生命周期,並將其掛鈎以手動控制 FX 應用程序生命周期。

這是該方法的一個示例,再次使用 Spring 引導:

package org.jamesd.examples.springfx;

import java.io.IOException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

@SpringBootApplication
public class App implements CommandLineRunner {

    @Autowired
    private ConfigurableApplicationContext context ;

    private void startUI()  {

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Main.fxml"));
            loader.setControllerFactory(context::getBean);
            Parent root = loader.load();
            Scene scene = new Scene(root);
            Stage stage = new Stage();
            stage.setScene(scene);
            stage.show();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }



    public static void main(String[] args) {
        SpringApplication.run(App.class, args) ;
    }


    @Override
    public void run(String... args) throws Exception {
        // perform additional configuration on context, as needed

        Platform.startup(this::startUI);
    }

}

請注意,在這種方法中,Spring Boot 正在控制自己的生命周期,因此它將“知道”在關機時調用任何@PreDestroy注釋的方法(下面的示例代碼在MessageBean中包含這樣的方法)。


為了完整起見,這里是其余的類、FXML 文件和配置,以使其成為一個完整的示例。 上述任一版本的App都可以使用這些文件:

org.jamesd.examples.springfx.Config:

package org.jamesd.examples.springfx;

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

@Configuration
public class Config {

    @Bean
    public MessageBean messageBean() {
        return new MessageBean();
    }

    @Bean
    public Controller controller() {
        return new Controller();
    }
}

org.jamesd.examples.springfx.Controller:

package org.jamesd.examples.springfx;

import org.springframework.beans.factory.annotation.Autowired;

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class Controller {

    @Autowired
    private MessageBean messageBean ;

    @FXML
    private Label welcomeLabel ;

    @FXML
    private void initialize() {
        welcomeLabel.setText(messageBean.getMessage());
    }
}

org.examples.jamesd.springfx.MessageBean:

package org.jamesd.examples.springfx;

import javax.annotation.PreDestroy;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "springfx")
public class MessageBean {

    private String message ;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @PreDestroy
    public void dispose() {
        System.out.println("Closing");
    }

}

org.jamesd.examples.springfx.Main.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>

<VBox alignment="CENTER" minWidth="200" minHeight="200" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.jamesd.examples.springfx.Controller">
    <Label fx:id="welcomeLabel" />
</VBox>

應用程序屬性:

springfx.message=Spring Boot JavaFX Application

模塊信息.java:

module org.jamesd.examples.springfx {
    requires transitive javafx.controls;
    requires javafx.fxml;
    requires spring.boot;
    requires spring.beans;
    requires spring.context;
    requires spring.core ;
    requires spring.boot.autoconfigure;
    requires java.annotation;

    opens org.jamesd.examples.springfx to javafx.fxml, spring.context, spring.beans, spring.core ;
    exports org.jamesd.examples.springfx;
}

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.jamesd.examples</groupId>
    <artifactId>springfx</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>14</maven.compiler.source>
        <maven.compiler.target>14</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>14</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>14</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.4.RELEASE</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <release>11</release>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.1</version>
                <configuration>
                    <mainClass>org.jamesd.examples.springfx.App</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM