FXMLLoader初始化和SpringBoot-@Configuration

Vic*_*son 4 java spring javafx spring-boot

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

GitHub:https : //github.com/mvpjava

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

在Spring Boot应用程序启动后,有一个名为initialize()的公共方法,我不知道如何调用它。我在类和fxml文件中到处都可以找到对它的引用,但没有发现。

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

如果有人能启发我,我将不胜感激。

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

@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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*s_D 7

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

  1. FXMLLoader 加载并解析FXML文件
  2. 如果FXML文件中的根元素具有fx:controller属性,则它将获得对该类实例的引用;否则,它将获取该类实例的引用。它通过将控制器类传递给来实现此目的controllerFactory(如果已设置),否则调用控制器类的默认构造函数。
  3. 具有fx:id属性的任何元素都将使用匹配的@FXML注释注入到控制器字段中
  4. FXMLLoader调用控制器的initialize()方法,如果它有一个。

在您的情况下,我假设您正在设置的控制器工厂FXMLLoader以委托给Spring应用程序上下文,即,我假设您有类似的东西

ApplicationContext appContext = ... ; // Spring bean factory
FXMLLoader loader = new FXMLLoader();
loader.setLocation(...);
loader.setControllerFactory(appContext::getBean);
Parent ui = loader.load();
Run Code Online (Sandbox Code Playgroud)

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

Object controller = appContext.getBean(ConsoleTabController.class);
Run Code Online (Sandbox Code Playgroud)

在上面的步骤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()方法,如果它有一个。

请注意,在这种情况下,实际上有两种不同的注入字段和两种不同的“初始化”方法。首先注入@Autowired(或@Inject)注释的“ Spring注入字段”,然后@PostConstruct调用“ Spring初始化方法”(注释)。之后,将注入“ FXML注入字段”(注解@FXML),然后initialize()调用“ FXML初始化方法”(称为)。您没有任何@PostConstruct的示例代码的方法,但是有一点要小心的是,这些方法会被调用之前@FXML-annotated字段都被初始化。