Spring Boot+JavaFX:每次获取Controller时创建新实例的方法
解决Spring Boot+JavaFX列表项共享控制器的问题
方案一:将控制器设置为原型作用域
你的控制器标注了@Component,Spring默认是单例模式,所以每次调用getBean()都会返回同一个实例。只需给控制器添加原型作用域注解,让Spring每次请求都创建新实例:
import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 也可直接写@Scope("prototype") public class ListItemController { // 控制器逻辑 }
原来的加载代码无需修改,因为applicationContext::getBean现在每次都会返回新的控制器实例,每个列表项都会绑定独立的控制器。
注意:原型bean的生命周期由开发者自行管理,Spring不会自动调用@PreDestroy方法,如果控制器持有数据库连接、IO流等资源,需要手动释放。
方案二:手动创建控制器并注入依赖
如果不想把控制器注册为Spring组件,可以手动创建控制器实例,再通过Spring的AutowireCapableBeanFactory自动注入依赖:
// 移除控制器类上的@Component注解 public class ListItemController { @Autowired private SomeService someService; // 依赖依然能被正常注入 // 控制器逻辑 } // 加载FXML的代码修改为: FXMLLoader fxmlLoader = new FXMLLoader(PATH_TO_FXML); ListItemController controller = new ListItemController(); // 让Spring注入控制器的依赖 applicationContext.getAutowireCapableBeanFactory().autowireBean(controller); fxmlLoader.setController(controller); VBox listItem = fxmlLoader.load(); contentArea.getChildren().add(listItem);
这种方式更灵活,适合不需要Spring完全管理控制器生命周期的场景。
方案三:用ObjectProvider获取原型实例
如果希望保持控制器的@Component注解,同时优雅地获取新实例,可以注入ObjectProvider来获取原型bean:
// 在创建列表项的类中注入ObjectProvider @Autowired private ObjectProvider<ListItemController> controllerProvider; // 加载FXML时: FXMLLoader fxmlLoader = new FXMLLoader(PATH_TO_FXML); // 每次调用getObject()都会得到新的控制器实例 fxmlLoader.setController(controllerProvider.getObject()); VBox listItem = fxmlLoader.load(); contentArea.getChildren().add(listItem);
ObjectProvider是Spring提供的工具类,专门用于处理原型bean的获取,避免直接调用applicationContext.getBean()带来的耦合。
推荐方案
如果控制器需要Spring管理初始化逻辑(比如@PostConstruct),优先选择方案一或方案三;如果控制器逻辑简单,不需要Spring完全管理,方案二更轻便。
内容的提问来源于stack exchange,提问作者DragonCoder
相关产品推荐
相关产品推荐

