JavaFX应用程序中的Spring应用程序上下文

时间:2016-09-07 19:45:24

标签: spring javafx dependency-injection autowired applicationcontext

我有兴趣在JavaFX应用程序中使用ApplicationContext。我问自己是否有一种更聪明的方法来处理ApplicationContext作为Application子类本身的属性。

@Configuration
@ComponentScan("...")
public class Gui extends Application {

   private AnnotationConfigApplicationContext context;

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

   /* (non-Javadoc)
    * @see javafx.application.Application#start(javafx.stage.Stage)
    */

    @Override
    public void start(Stage stage) throws Exception {       
      context = new AnnotationConfigApplicationContext(Gui.class);
      //...         
    }       
}

我的目的是将ApplicationContextGui.class分开,然后使用@Autowired注释在Gui.class中注入弹簧组件。

1 个答案:

答案 0 :(得分:2)

首先,将应用程序配置与Application子类分开。 JavaFX将为您创建Application子类的实例,并且该类应该只有一个实例。 Spring将创建任何配置类的实例,因此,即使您无法访问它们,最终也会得到Application类的多个实例,这不是预期用途。

至于您正在寻找的分离,我认为您想要的是将创建和与ApplicationContext的交互与构建和配置UI的工作分开,并使其与业务层交互对于应用程序等。但是,我认为你正在从你应该的方式向后看。 Application类,特别是其start()方法,是JavaFX应用程序的入口点。 FX框架在启动时执行一些内务处理(启动FX工具包等),创建该类的实例,并调用start方法。由于这是您进行应用程序基本组装的地方,因此创建ApplicationContext并从中获取一个或两个bean是自然而正确的地方。如果要将其与创建和配置UI分开,则应创建和配置应移动到其他位置的UI。 Application类的唯一责任应该是启动应用程序:这样就没有任何状态可以注入该类。

使用这种方法,最小的Spring驱动的FX应用程序可能如下所示:

AppConfig.java:

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

@Configuration
public class AppConfig {

    @Bean
    public Service service() {
        return new Service();
    }

    @Bean
    @Scope("prototype")
    public Gui gui() {
        return new Gui();
    }
}

Service.java:

public class Service {

    public String confirmationMessage() {
        return "You have been confirmed";
    }
}

Gui.java(请注意,现在这不是Application子类,但它几乎完成了所有GUI工作):

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;

public class Gui {

    @Inject
    private Service service ;

    private VBox view ;
    private Label label ;

    public Gui() {
        Button button = new Button("Press for confirmation");
        label = new Label();
        label.setVisible(false);
        button.setOnAction(e -> label.setVisible(true));

        view = new VBox(5, label, button);
        view.setPadding(new Insets(20));
        view.setAlignment(Pos.CENTER);
    }

    @PostConstruct
    private void init() {
        label.setText(service.confirmationMessage());
    }

    public Parent getView() {
        return view ;
    }
}

最后,Application类,Main.java。请注意,这并不能完成任何GUI工作:它只管理应用程序生命周期:创建ApplicationContext,从中获取表示主视图的bean,并在初级阶段显示它。所有实际的GUI工作都委托给MainView类,其实例由Spring管理。

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

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

public class Main extends Application {

    private AbstractApplicationContext context ;

    @Override
    public void start(Stage primaryStage) {
        context = new AnnotationConfigApplicationContext(AppConfig.class);
        Parent mainView = context.getBean(Gui.class).getView();
        primaryStage.setScene( new Scene(mainView) );
        primaryStage.show();
    }

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

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

您可以扩展此方法,以便它为表示层使用完整的MVC / MVP设计,如果需要则使用FXML等。