我有兴趣在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
注释在Gui.class
中注入弹簧组件。
答案 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等。