依赖注入和 JavaFX [英] Dependency Injection and JavaFX

查看:26
本文介绍了依赖注入和 JavaFX的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于 JavaFX 运行时想要实例化我的 Application 对象和我的所有控制器对象,我如何将依赖项注入到这些对象中?

Since JavaFX runtime wants to instantiate my Application object and all of my controller objects, how do I inject dependencies into these objects?

如果对象由 DI 框架实例化,例如 Spring,该框架将连接所有依赖项.如果我手动实例化对象,我将通过构造函数参数提供依赖项.但是我在 JavaFX 应用程序中做什么?

If objects were instantiated by a DI framework, like Spring, the framework would wire up all the dependencies. If I was instantiating the objects manually, I would provide the dependencies through constructor parameters. But what do I do in a JavaFX application?

谢谢!

推荐答案

您可以指定一个 控制器工厂.控制器工厂是一个函数,它将控制器类映射到将用作控制器的对象(可能,但不一定是该类的实例).

You can specify a controller factory for the FXMLLoader. The controller factory is a function that maps the controller class to an object (presumably, but not necessarily, an instance of that class) which will be used as the controller.

所以如果你想让 Spring 为你创建控制器实例,这可以很简单:

So if you want Spring to create the controller instances for you, this can be as simple as:

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);.

And now the FXMLLoader will create controller instances for a Class<?> c by calling context.getBean(c);.

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

So, e.g., you could have a configuration:

@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 框架,并且想手动"进行注入,则可以这样做,但这涉及使用相当多的反射.下面展示了如何(并将让您了解 Spring 为您做了多少丑陋的工作!):<​​/p>

If you're not using a DI framework, and you want to do the injection "by hand", you can do so, but it involves using quite a lot of reflection. The following shows how (and will give you an idea of how much ugly work Spring is doing for you!):

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 文件名相匹配,一切正常.)

Finally, you might want to check out afterburner.fx, which is a very lightweight (in all the best ways) JavaFX-specific DI framework. (It uses a convention-over-configuration approach, where you just match FXML file names to controller class names, and optionally CSS file names, and everything just works.)

这篇关于依赖注入和 JavaFX的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆