JavaFX Controller中@Autowire注入Spring Boot Service始终为null问题排查
问题:Spring Boot + JavaFX 中Controller注入Service报NullPointerException
我正在开发基于Spring Boot和JavaFX的应用,需将邮箱与密码存储至H2数据库。已通过JUnit测试验证数据库正常运行且可访问Spring Boot Repository,但在JavaFX Controller中通过@Autowire注入Spring Boot Service时出现NullPointerException,无法通过GUI调用业务逻辑。
相关代码
JavaFXController
@Component @FxmlView("start.fxml") @Service public class JavaFXController { @FXML private Label startLabel; @FXML private Label settingsLabel; @FXML private TextField emailAmazonMerchOnDemand; @FXML private PasswordField passwordAmazonMerchOnDemand; private Stage stage; private Scene scene; @Autowired private AmazonMerchOnDemandService amazonMerchOnDemandService; @FXML public void openSettingsSceneFromStartScene() throws IOException { Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("settings.fxml")); stage = (Stage)(startLabel.getScene().getWindow()); scene = new Scene(root); stage.setScene(scene); stage.show(); } @FXML public void saveLogins() { String emailAmazon = emailAmazonMerchOnDemand.getText(); String passwordAmazon = passwordAmazonMerchOnDemand.getText(); AmazonMerchOnDemand amazonMerchOnDemandLogin = new AmazonMerchOnDemand(); amazonMerchOnDemandLogin.setId(1L); amazonMerchOnDemandLogin.setEmail(emailAmazon); amazonMerchOnDemandLogin.setPassword(passwordAmazon); amazonMerchOnDemandService.saveLogin(amazonMerchOnDemandLogin); } }
JavaFXApplication
@SpringBootApplication public class JavaFXApplication extends Application { private ConfigurableApplicationContext applicationContext; @Override public void init() throws Exception { String[] args = getParameters().getRaw().toArray(new String[0]); this.applicationContext = new SpringApplicationBuilder().sources(PrintOnDemandSellerViewApplication.class).run(args); } @Override public void start(Stage stage) throws Exception { FXMLLoader loader = new FXMLLoader(); URL xmlUrl = getClass().getClassLoader().getResource("start.fxml"); loader.setLocation(xmlUrl); loader.setController(applicationContext.getBean(JavaFXController.class)); Parent root = loader.load(); Scene scene = new Scene(root); stage.setScene(scene); stage.show(); } @Override public void stop() throws Exception { this.applicationContext.close(); Platform.exit(); } }
AmazonMerchOnDemandService
@Service @Component public class AmazonMerchOnDemandService { public static WebDriver driver; private static int amountOfSales; @Autowired private AmazonMerchOnDemandRepository amazonMerchOnDemandRepository; public void saveLogin(AmazonMerchOnDemand amazonMerchOnDemand) { amazonMerchOnDemandRepository.save(amazonMerchOnDemand); } public void chromeDriverSetUp() { System.setProperty("webdriver.chrome.driver", "C:\Program Files (x86)\chromedriver.exe"); driver = new ChromeDriver(); driver.manage().window().maximize(); } public void login() { String email = amazonMerchOnDemandRepository.findById(1L).get().getEmail(); System.out.println("Email: " + email); String password = amazonMerchOnDemandRepository.findById(1L).get().getPassword(); System.out.println("Password: " + password); } }
AmazonMerchOnDemandRepository
@Repository public interface AmazonMerchOnDemandRepository extends CrudRepository <AmazonMerchOnDemand, Long> { }
PrintOnDemandSellerViewApplicationTests
@SpringBootTest(classes = JavaFXApplication.class) class PrintOnDemandSellerViewApplicationTests { @Autowired private AmazonMerchOnDemandRepository amazonMerchOnDemandRepository; @Autowired private AmazonMerchOnDemandSampleData amazonMerchOnDemandSampleData; @BeforeEach public void setupData() { amazonMerchOnDemandSampleData.createAmazonMerchOnDemandLogin(); } @Test public void testHasAmazonMerchOnDemandLoginRightPasswordAndRightEmail() { assertTrue(amazonMerchOnDemandRepository.existsById(1L)); Optional<AmazonMerchOnDemand> amazonMerchOnDemandOptional = amazonMerchOnDemandRepository.findById(1L); assertFalse(amazonMerchOnDemandOptional.isEmpty()); AmazonMerchOnDemand amazonMerchOnDemandLogin = amazonMerchOnDemandOptional.get(); assertEquals("password", amazonMerchOnDemandLogin.getPassword()); assertEquals("test@gmail.com", amazonMerchOnDemandLogin.getEmail()); } }
异常信息
Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:77) at jdk.internal.reflect.GeneratedMethodAccessor37.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at javafx.base@19/com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:275) at javafx.fxml@19/com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:84) at javafx.fxml@19/javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1854) ... 29 more Caused by: java.lang.NullPointerException at com.example.printondemandsellerview.JavaFXController.saveLogins(JavaFXController.java:53) ... 40 more
排查建议
- 检查
start.fxml中是否存在fx:controller属性,若有必须删除。因为你已通过loader.setController(applicationContext.getBean(JavaFXController.class))手动指定Spring管理的Controller实例,FXML文件中再指定会导致FXMLLoader创建新的非Spring管理实例,该实例的amazonMerchOnDemandService会为null。 - 清理冗余注解:
JavaFXController同时标注了@Component、@FxmlView、@Service,仅保留@Component或@Service其中一个即可,避免Spring重复创建实例。 - 简化
AmazonMerchOnDemandService注解:同时标注@Service和@Component,保留@Service即可。 - 验证Spring上下文加载情况:在
JavaFXApplication的start方法中打印applicationContext.getBean(JavaFXController.class).amazonMerchOnDemandService,确认Spring是否完成注入。 - 修正场景加载方式:若
settings.fxml对应的Controller也需要Spring注入,不能使用FXMLLoader.load()静态方法,需像加载start.fxml一样从Spring上下文获取Controller实例并设置给FXMLLoader,否则新场景的Controller会是非Spring管理实例。 - 确认主启动类正确性:检查
JavaFXApplication的init方法中SpringApplicationBuilder.sources()传入的PrintOnDemandSellerViewApplication是否为正确的主启动类,避免Spring扫描范围错误导致Bean未加载。
内容的提问来源于stack exchange,提问作者Maik
相关产品推荐
相关产品推荐

