FXMLLoader初始化和SpringBoot - @Configuration

时间:2017-09-02 15:16:32

标签: java spring spring-boot javafx

我有一个教程中的问题 MVP将Spring Boot与JavaFX集成

GitHub:https://github.com/mvpjava

Youtube:https://www.youtube.com/watch?v=hjeSOxi3uPg

其中有一个名为 initialization()的公共方法,我不知道在Spring启动应用程序启动后如何调用它。我在类和fxml文件中到处查看它可以引用它,我找不到。

我想知道如何调用此方法,因为我还想对JavaFX控件进行一些初始化。我尝试使用@PostConstruct,但这是错误的,因为所有bean都是在创建任何JavaFX控件之前创建的,因此我得到空指针异常。

如果有人能在这件事上给我启发,我将非常感激。

这是我提到的公共方法 initialization()的类。

@Component
public class ConsoleTabController {

    @FXML private TextArea missionOverviewText;
    @FXML private ListView<String> missionsList;

    @Autowired @Qualifier("stringPrintWriter")
    private PrintWriter stackTraceWriter;

    @Autowired MissionsService service;
    private TabPaneManger tabManager;

    public void initialize() {
        ObservableList<String> missions = FXCollections.observableArrayList("Apollo", "Shuttle", "Skylab");
        missionsList.setItems(missions);
    }

    @FXML
    private void onMouseClicked(MouseEvent event) {
        missionOverviewText.clear();
        final String selectedItem = missionsList.getSelectionModel().getSelectedItem();
        missionOverviewText.positionCaret(0);
        missionOverviewText.appendText(getInfo(selectedItem));
    }

    @Autowired
    private void setTabManager(TabPaneManger tabManager){
        this.tabManager = tabManager;
    }

    public String getInfo(String selectedItem) {
        String missionInfo = null ;

        try {
            missionInfo = service.getMissionInfo(selectedItem); 
            getLog().appendText("Sucessfully retrieved mission info for " + selectedItem + "\n");
        } catch (IOException exception) {
            exception.printStackTrace (stackTraceWriter);
            getLog().appendText(stackTraceWriter.toString() + "\n");
        }
        return missionInfo;
    }

    public TextArea getMissionOverviewText() {
        return missionOverviewText;
    }

    public ListView<String> getMissionsList() {
        return missionsList;
    }

    private TextArea getLog(){
        return tabManager.getVisualLog();
    }
}

1 个答案:

答案 0 :(得分:4)

initialize()调用FXMLLoader方法(我认为你的意思)。通常,对于FXMLLoader,执行顺序为:

  1. FXMLLoader加载FXML文件并解析它
  2. 如果FXML文件中的根元素具有fx:controller属性,则它会获得对该类实例的引用;它通过将控制器类传递给controllerFactory(如果已设置)或者通过调用控制器类的默认构造函数来完成此操作。
  3. 具有fx:id属性的所有元素都会注入到匹配@FXML注释的控制器字段中
  4. FXMLLoader会调用控制器的initialize()方法(如果有)。
  5. 在您的情况下,我假设您将FXMLLoader的控制器工厂设置为委托给Spring应用程序上下文,即我假设您有类似

    的内容
    ApplicationContext appContext = ... ; // Spring bean factory
    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(...);
    loader.setControllerFactory(appContext::getBean);
    Parent ui = loader.load();
    

    这意味着将通过将控制器类传递给Spring bean工厂的getBean(...)方法来创建控制器实例。因此,如果FXML文件具有fx:controller="ConsoleTabController",则FXMLLoader实质上会调用

    Object controller = appContext.getBean(ConsoleTabController.class);
    

    在上面的第2步中。 Spring应用程序上下文创建一个ConsoleTabController实例(假设您已将控制器bean配置为具有原型范围,您应该这样做),注入任何@AutoWired - 带注释的属性,调用任何@PostConstruct - 注释方法,然后将控制器提供给FXMLLoader。因此,当您将Spring bean工厂用作控制器工厂时,执行的总体顺序是

    1. FXMLLoader加载FXML文件并解析它
    2. 如果FXML文件中的根元素具有fx:controller属性:
            
      1. Spring bean工厂创建控制器类的实例     
      2. Spring bean工厂将任何@Autowired - 带注释的属性注入控制器实例     
      3. Spring bean工厂在控制器实例上调用任何@PostConstruct - 带注释的方法     
      4. 控制器实例返回FXMLLoader
    3. 具有fx:id属性的所有元素都会被@FXML注入到FXMLLoader注释的控制器字段中
    4. FXMLLoader调用控制器的initialize()方法(如果有)。

    请注意,基本上有两种不同类型的注入字段,以及两种不同类型的&#34;初始化&#34;此方案中的方法。首先注入&#34; Spring注入字段&#34;,注释@Autowired(或@Inject),然后注入&#34; Spring初始化方法&#34; (带注释的@PostConstruct)被调用。之后,&#34; FXML注入字段&#34; (注释@FXML)被注入,然后&#34; FXML初始化方法&#34; (调用initialize()的那个)被调用。您的示例代码中没有任何@PostConstruct方法,但要注意的一点是,在<{em> @FXML之前调用这些方法 - 注释字段已初始化。