由于JavaFX运行时希望实例化我的Application对象和所有控制器对象,如何将依赖项注入这些对象?
如果对象是由像DI一样的DI框架实例化的,那么框架将连接所有依赖项。如果我手动实例化对象,我会通过构造函数参数提供依赖项。但是我在JavaFX应用程序中该怎么办?
谢谢!
答案 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...
// ...
将通过调用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();
}
// ...
}
如果你没有使用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;
}