依赖注入和JavaFX

乔治 :

由于JavaFX运行要实例化我的应用程序对象和所有我的控制器对象,我怎么依赖注入这些对象呢?

如果对象是一个DI框架实例,如Spring,该框架将线了所有的依赖。如果我是手动实例化对象,我将通过构造函数的参数提供的依赖关系。但是我在JavaFX应用程序吗?

谢谢!

James_D:

您可以指定一个控制器出厂FXMLLoader控制器工厂是控制器类映射到一个对象的功能(可能的,但不是必须地,那个类的一个实例),其将被用作控制器。

所以,如果你希望Spring为你创建控制器的情况下,这可以是简单的:

ApplicationContext context = ... ;

FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
loader.setControllerFactory(context::getBean);
Parent root = loader.load();
SomeController controller = loader.getController(); // if you need it...
// ...

而现在FXMLLoader将创建一个控制器实例Class<?> c调用context.getBean(c);

因此,例如,你可以有一个配置:

@Configuration
public class AppConfig {

    @Bean
    public MyService service() {
        return new MyServiceImpl();
    }

    @Bean
    @Scope("prototype")
    public SomeController someController() {
        return new SomeController();
    }

    // ...
}

public class SomeController {

    // injected by FXMLLoader:
    @FXML
    private TextField someTextField ;

    // Injected by Spring:
    @Inject
    private MyService service ;

    public void initialize() {
        someTextField.setText(service.getSomeText());
    }

    // event handler:
    @FXML
    private void performAction(ActionEvent e) {
        service.doAction(...);
    }
}

如果你不使用DI框架,你想要做注射“手动”,你可以这样做,但它涉及使用相当多的反思。下面显示了如何(以及会给你的春天是多么丑陋的工作做你的想法!):

FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/fxml"));
MyService service = new MyServiceImpl();
loader.setControllerFactory((Class<?> type -> {
    try {
        // look for constructor taking MyService as a parameter
        for (Constructor<?> c : type.getConstructors()) {
            if (c.getParameterCount() == 1) {
                if (c.getParameterTypes()[0]==MyService.class) {
                    return c.newInstance(service);
                }
            }
        }
        // didn't find appropriate constructor, just use default constructor:
        return type.newInstance();
    } catch (Exception exc) {
        throw new RuntimeException(exc);
    }
});
Parent root = loader.load();
// ...

然后就去做

public class SomeController {

    private final MyService service ;

    public SomeController(MyService service) {
        this.service = service ;
    }

    // injected by FXMLLoader:
    @FXML
    private TextField someTextField ;

    public void initialize() {
        someTextField.setText(service.getSomeText());
    }

    // event handler:
    @FXML
    private void performAction(ActionEvent e) {
        service.doAction(...);
    }
}

最后,你可能想看看afterburner.fx,这是一个非常轻量级(在所有的最佳途径)JavaFX的具体DI框架。(它使用约定优于配置的方法,在这里你只是比赛FXML文件名控制器类名和可选的CSS文件名,一切都只是工作。)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章