この記事は JavaFX Advent Calendar 2015 - Qiita の 21 日目の記事です。
昨日は @fukai_yas さんの ScalaFXでのListViewの扱い でした。
明日は @orekyuu さんです。
JavaFX を Spring Boot から起動してみます。
といっても、素の Spring と連携させる方法はすでに多く情報が公開されています。
JavaFXのControllerにおけるSpringBeanのインジェクションについて - タツノオトシゴの日記
なので、 Spring Boot から起動するのもほぼ同じ方法でいけます。
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.3.1.RELEASE'
}
}
apply plugin: 'java'
apply plugin: 'spring-boot'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
compileJava.options.encoding = 'UTF-8'
repositories {
mavenCentral()
}
dependencies {
compile 'org.springframework.boot:spring-boot-starter'
}
まずは普通に Spring Boot 用の build.gradle
を用意して。。。
package gl8080.javafx;
import java.io.IOException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
@SpringBootApplication
public class Main extends Application { // ★Application を継承
private static ConfigurableApplicationContext context;
public static void main(String[] args) throws IOException {
// ★ApplicationContext は後で使うので static 変数に保存しておく
context = SpringApplication.run(Main.class, args); // ★Spring Boot を起動
launch(args); // ★JavaFX を起動
}
@Override
public void start(Stage primaryStage) throws Exception {
// ★自作の FXMLLoader を Spring のコンテナから取得
MySpringFXMLLoader loader = context.getBean(MySpringFXMLLoader.class);
// ★fxml をロード
Parent root = loader.load("sample.fxml");
// ★あとは普通の JavaFX と同じ
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
@Override
public void stop() throws Exception {
context.close(); // ★アプリ終了時に stop() メソッドがコールバックされるので、 Spring コンテナを終了させる
}
}
起動用のクラスを作ります。
クラス自体は JavaFX の Application
を継承して、 JavaFX と同じ感じで作ります。
そして、 main()
メソッドの先頭で Spring Boot を起動してから JavaFX を起動(launch()
)させます。
start()
メソッドが呼びだされたら、 main()
メソッドで保存しておいた ConfigurableApplicationContext
から自作の FXMLLoader
を取得します。
自作の FXMLLoader
から fxml をロードしたら、あとは普通の JavaFX と同じです。
Spring Boot の終了処理は、 Application
クラスの stop()
メソッドがアプリケーション終了時にコールバックされることを利用して、そこで実行するようにしています。
自作の FXMLLoader
は、以下のような感じです。
package gl8080.javafx;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
@Component // ★コンポーネントとして登録
public class MySpringFXMLLoader {
@Autowired
private ApplicationContext context;
public Parent load(String path) throws IOException {
FXMLLoader loader = new FXMLLoader(); // ★オリジナルの FXMLLoader を生成
loader.setControllerFactory(this.context::getBean); // ★ControllerFactory に ApplicationContext を利用する
return loader.load(MySpringFXMLLoader.class.getClassLoader().getResourceAsStream(path));
}
}
処理自体は、ほとんどオリジナルの FXMLLoader
に丸投げです。
唯一違うのが、 Controller
のインスタンスを生成するための ControllerFactory
を設定しているところです。
FXMLLoader
の setControllerFacrorey()
には javafx.util.Callback
を実装したオブジェクトを渡します。
このインターフェースは関数型インターフェースになっていて、 Controller
の Class<?>
を受け取り、 Controller
のインスタンスを返す必要があります。
それは、まさしく ApplicationContext#getBean()
と一致するので、メソッド参照を使ってセットしています。
こうすることで、 Controller
のインスタンスが Spring のコンテナから取得されるようになります。
package gl8080.javafx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
@Component
public class MyController {
@FXML
private Label label;
@Autowired
private MyBean bean;
@FXML
public void onClickButton() {
String text = this.bean.getText();
this.label.setText(text);
}
}
コントローラクラスです。
Spring の @Autowired
で他のビーンをインジェクションしています。
ボタンを押したら、ラベルの文字列をビーンが返した値で書き換えるだけの単純な実装です。
package gl8080.javafx;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
public String getText() {
return "Hello Spring Boot!!";
}
}
MyBean
の実装はこんな感じ。
実際に動かしてみます。
問題なく連携できました!
コードは GitHub にあげています ( https://github.com/opengl-8080/javafx-and-spring-boot ) 。
おまけ
これで終わるのはアレなので、 Java EE のアドベントカレンダー で作ったライフゲームを JavaFX に移植してみました。
といっても、編集機能とかまで移植している余裕は、時間的にも体力的にもなかったので、とりあえずサンプルのゲーム定義だけを動かせるようにしました。
コードはこちら( https://github.com/opengl-8080/lifegame-javafx )です。
では、今回も彼に活躍していただきましょう!
↓
(;゚д゚)デューーーーーーーーーーーーーーーーーーーーーーク!!!!