Geo*_*rge 12 java dependency-injection javafx
由于JavaFX运行时希望实例化我的Application对象和所有控制器对象,如何将依赖项注入这些对象?
如果对象由像DI一样的DI框架实例化,那么框架将连接所有依赖项.如果我手动实例化对象,我会通过构造函数参数提供依赖项.但是我在JavaFX应用程序中该怎么办?
谢谢!
Jam*_*s_D 23
您可以为其指定控制器工厂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...
// ...
Run Code Online (Sandbox Code Playgroud)
现在,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();
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
同
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(...);
}
}
Run Code Online (Sandbox Code Playgroud)
如果你没有使用DI框架,并且你想"手动"进行注射,你可以这样做,但它涉及使用相当多的反射.以下显示了如何(并且会让您了解Spring为您做了多少丑陋工作!):
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();
// ...
Run Code Online (Sandbox Code Playgroud)
然后就做
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(...);
}
}
Run Code Online (Sandbox Code Playgroud)
最后,您可能需要查看afterburner.fx,这是一个非常轻量级(在所有最佳方式中)特定于JavaFX的DI框架.(它使用一种约定优于配置的方法,在这种方法中,您只需将FXML文件名与控制器类名称以及可选的CSS文件名匹配,并且一切正常.)
| 归档时间: |
|
| 查看次数: |
8428 次 |
| 最近记录: |