JavaFX and Spring - beans doesn't Autowire

前端 未结 1 629
醉话见心
醉话见心 2020-12-29 16:19

I have problems with combining JavaFX and Spring. I have simple JavaFX application, which works fine. Now I am trying to add some Spring to it. I followed JavaFX 2 with Spri

相关标签:
1条回答
  • 2020-12-29 16:44

    The FXMLLoader.load(URL, ResourceBundle) method you are calling is a static method - so it actually pays no attention to the FXMLLoader instance you instantiated, and consequently ignores the controllerFactory which references your Spring bean factory.

    Rewrite your SpringFXMLLoader class as follows:

    public class SpringFxmlLoader {
    
        private static final ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringApplicationConfig.class);
    
        public Object load(String url, String resources) {
            FXMLLoader loader = new FXMLLoader();
            loader.setControllerFactory(clazz -> applicationContext.getBean(clazz));
            loader.setLocation(getClass().getResource(url));
            loader.setResources(ResourceBundle.getBundle(resources));
            try {
                return loader.load();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    This uses the instance method loader.load() which will use your controller factory: i.e. it will use Spring to instantiate the controller.

    The reason you see the controller loaded twice is that by default the bean factory gives the controller singleton scope and makes it eagerly created, so as soon as you create the bean factory (applicationContext) it creates a controller. That controller will have its dataProvider initialized (but only after the constructor has completed, of course). Then the call to the static FXMLLoader.load(...) method creates a second controller by the usual mechanism (i.e. by calling its no-arg constructor). That instance will not have its dataProvider initialized at any time.

    As an aside, you probably don't want controllers to be singletons. If you were to load your FXML file twice, to get two instances of the Parent, you would likely need each instance to have its own controller, otherwise strange behavior would ensue. I would recommend making the controller a prototype (which means the bean factory will create a new instance every time one is requested, instead of reusing a single instance). You can do this with the following in your config class:

    @Configuration
    @ComponentScan(basePackages = {"mycompany.imageviewer.controller", "mycompany.imageviewer.dataprovider.impl" })
    public class SpringApplicationConfig {
        private static final Logger LOG = Logger.getLogger(SpringApplicationConfig.class);
    
        @Bean
        public DataProvider dataProvider() {
            LOG.debug("Initializing dataProvider via SpringApplicationConfig");
            return new DataProviderImpl();
        }
    
        @Bean
        @Scope("prototype")
        public ImageViewerController imageViewerController() {
            LOG.debug("Initializing ImageViewerController via SpringApplicationConfig");
            return new ImageViewerController();
        }
    }
    
    0 讨论(0)
提交回复
热议问题