LoginSignup
1
2

More than 5 years have passed since last update.

Spring FrameworkでJavaFXプログラミングを楽にしたかった

Posted at

概要

 実のところN番煎じではありますが……と言うかこの記事が無かった段階で試行錯誤していたのでベストプラクティスではないかも知れません。

ポイント

ComponentScanするクラスでの記述

MainApp.java
/**
 * 起動用クラス
 * @author ysrken
 */
@ComponentScan
public class MainApp extends Application {
    private static ConfigurableApplicationContext context;

    /**
     * main関数
     * @param args コマンドライン引数
     * @throws Exception 実行時例外
     */
    public static void main(String[] args) throws Exception {
        // このcontextは今後使い回すので、あえて上記のようにstatic変数にした
        context = new AnnotationConfigApplicationContext(MainApp.class);
        launch(args);
    }

    /**
     * JavaFXの起動処理
     * @param stage Stage情報
     * @throws Exception 実行時例外
     */
    public void start(Stage stage) throws Exception {
        // 無難に生成するが、getBeanしているのがポイント
        FXMLLoader loader = new FXMLLoader();
        loader.setControllerFactory(MainApp.getApplicationContext()::getBean);
        Parent rootNode = (Parent) loader.load(getClass().getResourceAsStream("/fxml/MainView.fxml"));
        Scene scene = new Scene(rootNode);
        stage.setScene(scene);

        mainStage.show();
    }

    /**
     * ApplicationContextを引き回すために使用
     * @return 共用するApplicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return context;
    }

    /**
     * JavaFXの終了処理
     * @throws Exception 実行時例外
     */
    @Override
    public void stop() throws Exception {
        context.close();
    }
}

 ここで重要なのは「ConfigurableApplicationContext context」の部分で、この変数をgetApplicationContext()で他のウィンドウ生成時に利用します。
 つまり、FXMLLoaderを利用する際、単にnew FXMLLoader()とするだけではなく、loader.setControllerFactory(MainApp.getApplicationContext()::getBean);としてcontextをセットしておきます。こうすることで、Spring FrameworkのDIがウィンドウのControllerおよびModelにも及びます。

Controllerでの記述

Controller.java
@Component
//@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class Controller{
    /**
     * Model
     */
    @Autowired
    Model model;

    /**
     * 初期化
     */
    public void initialize() {
        ~~~
    }
}

 前述のようにcontextをセットしておくことにより、@AutowiredするだけでModelが読み込まれます。当該ControllerおよびModelを複数個作成する予定がある場合は、SCOPE_PROTOTYPE指定をしているコメントアウトを外しましょう。

Modelでの記述

Model.java
@Component
//@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class Model{
    /**
     * 初期化
     */
    publicModel() {
        ~~~
    }
}

 Modelでも@Autowiredが効くのは嬉しいですね。

その他での記述

 DIしたいクラスにはだいたい@Component等が付いていると思いますが、上記Controller関係以外で、内部に@Autowiredが使われているクラスのインスタンスを生成する際は次のように書きましょう。

sample.java
@Component
public class SampleClass {
    /**
     * Model
     */
    @Autowired
    Hoge hoge;

    ~~~~~~
}

// OK
final SampleClass x = MainApp.getApplicationContext().getBean(SampleClass.class);
// NG
final SampleClass y = new SampleClass();

参考資料

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2