依赖注入和JavaFX

时间:2016-11-11 00:21:31

标签: java javafx dependency-injection

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

如果对象是由像DI一样的DI框架实例化的,那么框架将连接所有依赖项。如果我手动实例化对象,我会通过构造函数参数提供依赖项。但是我在JavaFX应用程序中该怎么办?

谢谢!

2 个答案:

答案 0 :(得分:19)

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

因此,如果您希望Spring为您创建控制器实例,可以这么简单:

FXMLLoader

现在,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... // ... 将通过调用FXMLLoaderClass<?> c创建控制器实例。

因此,例如,您可以进行配置:

context.getBean(c);

@Configuration
public class AppConfig {

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

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

    // ...
}

如果你没有使用DI框架,并且你想“手动”进行注射,你可以这样做,但它涉及使用相当多的反射。以下显示了如何(并将让您了解Spring为您做了多少丑陋工作!):<​​/ p>

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

然后再做

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

最后,您可能需要查看afterburner.fx,这是一个非常轻量级(在所有最佳方式中)特定于JavaFX的DI框架。 (它使用了一种约定优于配置的方法,在这种方法中,您只需将FXML文件名与控制器类名称以及可选的CSS文件名匹配,并且一切正常。)

答案 1 :(得分:0)

我使用FXMLLoader类的setControllerFactory方法设置此序列化程序使用的控制器工厂。

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext();
        ctx.register(AppConfig.class);
        ctx.refresh();
        FXMLLoader loader = new FXMLLoader(getClass().getResource("../view/sample.fxml"));
        loader.setControllerFactory(ctx::getBean);

        Parent root = loader.load();
        Controller controller = loader.getController();
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 925, 400));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);

    }
}

然后使用@component来控制类

  @Component
        public class Controller {
            @Autowired
            private ItemController itemController;
            @FXML
            private TextField item;
            @FXML
            private TextField quantity;
        }