dependency injection和JavaFX
由于JavaFX运行时想要实例化我的应用程序对象和我的所有控制器对象,我如何注入依赖关系到这些对象?
如果对象是由DI框架实例化的,就像Spring一样,框架将连接所有的依赖关系。 如果我手动实例化对象,我会通过构造函数参数提供依赖关系。 但是,我在JavaFX应用程序中做什么?
谢谢!
您可以为FXMLLoader
指定一个控制器工厂 。 控制器工厂是一个将控制器类映射到将用作控制器的对象(可能是,但不一定是该类的一个实例)的函数。
所以如果你想让Spring为你创build控制器实例,可以这样简单:
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
将通过调用context.getBean(c);
为Class<?> c
创build控制器实例context.getBean(c);
。
所以,例如,你可以有一个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框架,并且想“手动”注入,你可以这样做,但是它涉及到很多reflection。 下面的内容展示了如何(并且会给你一个关于Spring为你做了多less难看的工作的想法!):
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框架。 (它使用了一种常规的configuration方法,只要将FXML文件名与控制器类的名称以及可选的CSS文件名进行匹配,一切正常。)
- SpringValue语言(SpEL)与@Value:美元与哈希($与#)
- Reader Monaddependency injection:多重依赖,嵌套调用
- 为什么要在内置的ASP.NET Core DI容器上使用第三方DI容器?
- 什么是javax.inject.named注释应该用于?
- 如何使用具有“贪婪”构造函数的Scan来使用具有通用未closurestypes的StructureMap
- Spring @Autowired如何工作
- 鉴于ES2015,dependency injection和库抽象,2016年我的理想模块应该是什么样子?
- 春季Autowiring类与界面?
- Spring:命名空间vs contextConfigLocation web.xml中的init参数