我有兴趣在 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);
//...
}
}
我的目的是将ApplicationContext
与Gui.class
分开,并进一步使用@Autowired
注释在Spring组件中注入(inject)Gui.class
.
最佳答案
首先,将应用程序配置与 Application
子类分开。 JavaFX 将为您创建一个 Application 子类的实例,并且该类应该只有一个实例。 Spring 将创建任何配置类的实例,因此,即使您无权访问它们,您最终也会获得 Application 类的多个实例,这不是预期的用途。
至于您正在寻找的分离,我认为您想要的是将 ApplicationContext
的创建和交互与构建和配置 UI 的工作分开,并使其与应用程序的业务层等。但是,我认为您正在以应有的方式向后看待这个问题。 Application
类,特别是其 start()
方法,是 JavaFX 应用程序的入口点。 FX 框架在启动时执行一些内务处理(启动 FX 工具包等),创建该类的实例,并调用 start 方法。由于这是您进行应用程序的基本组装的地方,因此它是创建 ApplicationContext
并从中获取一两个 bean 的自然且正确的位置。如果您想将其与 UI 的创建和配置分开,则应将 UI 的创建和配置移至其他地方。 Application
类的唯一职责应该是启动应用程序:这样就根本没有状态可以注入(inject)到该类中。
使用这种方法,一个最小的 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();
}
}
服务.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 工作都委托(delegate)给 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 等。
关于JavaFX 应用程序中的 Spring 应用程序上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39377920/