You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+JavaFX打包JAR启动报错:类找不到问题求助

Spring Boot 3.4.5 + JavaFX 打包后启动服务报错:ClassNotFoundException

问题描述

开发基于Spring Boot 3.4.5与JavaFX的应用,通过带启停按钮的GUI控制Spring Boot服务的启动、重启与停止。IDE开发模式下运行正常,但构建fat jar后运行时,点击启动服务按钮抛出ClassNotFoundException,找不到org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer类。

错误日志

[22:48:10] ▶ Starting server...
[22:48:10] ❌ Failed to start server: Unable to instantiate factory class [org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer] for factory type [org.springframework.context.ApplicationContextInitializer]
[22:48:10] 📋 java.lang.IllegalArgumentException: Unable to instantiate factory class [org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer] for factory type [org.springframework.context.ApplicationContextInitializer]
[22:48:10] 📋 at org.springframework.core.io.support.SpringFactoriesLoader$FailureHandler.lambda$throwing$0(SpringFactoriesLoader.java:641)
[22:48:10] 📋 at org.springframework.core.io.support.SpringFactoriesLoader$FailureHandler.lambda$handleMessage$3(SpringFactoriesLoader.java:665)
[22:48:10] 📋 at org.springframework.core.io.support.SpringFactoriesLoader.instantiateFactory(SpringFactoriesLoader.java:227)
[22:48:10] 📋 at org.springframework.core.io.support.SpringFactoriesLoader.load(SpringFactoriesLoader.java:202)
[22:48:10] 📋 at org.springframework.core.io.support.SpringFactoriesLoader.load(SpringFactoriesLoader.java:158)
[22:48:10] 📋 at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:466)
[22:48:10] 📋 at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:462)
[22:48:10] 📋 at org.springframework.boot.SpringApplication.<init>(SpringApplication.java:278)
[22:48:10] 📋 at org.springframework.boot.SpringApplication.<init>(SpringApplication.java:257)
[22:48:10] 📋 at org.springframework.boot.SpringApplication.run(SpringApplication.java:1362)
[22:48:10] 📋 at org.springframework.boot.SpringApplication.run(SpringApplication.java:1351)
[22:48:10] 📋 at com.novastream.config.ServerControlGUI.lambda$startServer$16(ServerControlGUI.java:403)
[22:48:10] 📋 at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1848)
[22:48:10] 📋 at java.base/java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1840)
[22:48:10] 📋 at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:507)
[22:48:10] 📋 at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1458)
[22:48:10] 📋 at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:2034)
[22:48:10] 📋 at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:189)
[22:48:10] 📋 Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
[22:48:10] 📋 at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
[22:48:10] 📋 at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
[22:48:10] 📋 at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:528)
[22:48:10] 📋 at java.base/java.lang.Class.forName0(Native Method)
[22:48:10] 📋 at java.base/java.lang.Class.forName(Class.java:578)
[22:48:10] 📋 at java.base/java.lang.Class.forName(Class.java:557)
[22:48:10] 📋 at org.springframework.util.ClassUtils.forName(ClassUtils.java:321)
[22:48:10] 📋 at org.springframework.core.io.support.SpringFactoriesLoader.instantiateFactory(SpringFactoriesLoader.java:220)
[22:48:10] 📋 ... 15 more

核心代码片段

主入口类

package com.novastream;

import com.novastream.config.MediaConfig;
import com.novastream.config.ServerControlGUI;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync
@SpringBootApplication
@EnableConfigurationProperties(MediaConfig.class)
public class NovastreamBackendApplication {

  public static void main(String[] args) {
    System.setProperty("java.awt.headless", "false");
    ServerControlGUI.launch(ServerControlGUI.class);
  }
}

ServerControlGUI核心代码

@Component
public class ServerControlGUI extends Application {
@Override
  public void start(Stage primaryStage) {
    primaryStage.initStyle(StageStyle.TRANSPARENT);

    DropShadow shadow = new DropShadow(20, Color.BLACK);
    shadow.setOffsetX(0);
    shadow.setOffsetY(10);

    VBox root = createMainLayout(primaryStage);
    root.setEffect(shadow);
    root.getStyleClass().add("main-container");

    Rectangle clip = new Rectangle(800, 600);
    clip.setArcWidth(16);
    clip.setArcHeight(16);
    root.setClip(clip);

    Scene scene = new Scene(root, 800, 600);
    scene.setFill(Color.TRANSPARENT);
    scene
      .getStylesheets()
      .add(getClass().getResource("/static/gui.css").toExternalForm());

    primaryStage.setScene(scene);
    primaryStage.setTitle("NovaStream");
    primaryStage.show();
    animateStartup(primaryStage);

    primaryStage.setOnCloseRequest(e -> {
      stopServer();
      Platform.exit();
      System.exit(0);
    });

    setupSystemStreamRedirection();
  }

  private VBox createControlPanel() {
    VBox panel = new VBox();
    panel.getStyleClass().add("control-panel");

    Label title = new Label("Server Controls");
    title.getStyleClass().add("control-title");

    HBox controls = new HBox();
    controls.getStyleClass().add("controls-container");

    startRestartBtn =
      createActionButton("▶ Start Server", "start-button", this::startServer);
    stopBtn =
      createActionButton("⏹ Stop Server", "stop-button", this::stopServer);
    clearLogsBtn =
      createActionButton("🗑 Clear Logs", "clear-button", this::clearLogs);

    stopBtn.setDisable(true);
    clearLogsBtn.setDisable(true);

    controls.getChildren().addAll(startRestartBtn, stopBtn, clearLogsBtn);
    panel.getChildren().addAll(title, controls);

    return panel;
  }
  private void startServer() {
    if (loadingIndicator.isVisible() || serverRunning) return;

    Platform.runLater(() -> {
      loadingIndicator.setVisible(true);
      updateStatusLabel("Starting...", "status-starting");
      startRestartBtn.setDisable(true);
      stopBtn.setDisable(true);
    });

    CompletableFuture.runAsync(() -> {
      try {
        appendLog("▶ Starting server...");

        springContext =
          SpringApplication.run(NovastreamBackendApplication.class);
        serverRunning = true;
        startTime = LocalDateTime.now();

        Platform.runLater(() -> {
          loadingIndicator.setVisible(false);
          updateStatusLabel("Running", "status-running");
          startRestartBtn.setDisable(false);
          stopBtn.setDisable(false);

          updateStartRestartButton();
          startUptimeTimer();
        });
        appendLog("✅ Server started successfully");
        appendLog("🌐 Server running on http://localhost:8080");
      } catch (Exception e) {
        Platform.runLater(() -> {
          loadingIndicator.setVisible(false);
          updateStatusLabel("Failed", "status-failed");
          startRestartBtn.setDisable(false);
        });
        appendLog("❌ Failed to start server: " + e.getMessage());
        e.printStackTrace();
      }
    });
  }
}

pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.5</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.novastream</groupId>
    <artifactId>novastream-backend</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>novastream-backend</name>
    <description>NovaStream Backend</description>
    <url />
    <licenses>
        <license />
    </licenses>
    <developers>
        <developer />
    </developers>
    <scm>
        <connection />
        <developerConnection />
        <tag />
        <url />
    </scm>
    <properties>
        <java.version>23</java.version>
        <javafx.version>21</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>3.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>${javafx.version}</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-graphics</artifactId>
            <version>${javafx.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>3.4.5</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

问题根源

ConfigurationWarningsApplicationContextInitializer类在Spring Boot 3.x版本中已被移除,但spring-boot-devtools依赖的META-INF/spring.factories文件中仍保留了该类的配置项。打包fat jar时,该配置被包含进去,导致Spring应用启动时尝试加载这个已不存在的类,从而抛出ClassNotFoundException。

解决步骤

  1. 移除spring-boot-devtools依赖
    spring-boot-devtools是开发环境专属工具,生产打包无需包含,直接删除pom.xml中的对应依赖:

    <!-- 删除此段依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    
  2. 清理spring.factories配置(若需要)
    如果移除devtools后仍有问题,检查项目中是否存在src/main/resources/META-INF/spring.factories文件,删除其中所有关于ConfigurationWarningsApplicationContextInitializer的配置行。

  3. 优化Spring Boot打包插件配置
    确保打包插件正确识别主类,避免依赖缺失。可在spring-boot-maven-plugin中明确指定主类:

    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>3.4.5</version>
        <executions>
            <execution>
                <goals>
                    <goal>repackage</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <excludes>
                <exclude>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                </exclude>
            </excludes>
            <!-- 明确指定主类 -->
            <mainClass>com.novastream.NovastreamBackendApplication</mainClass>
        </configuration>
    </plugin>
    
  4. JavaFX打包适配(针对Launch4J)
    若后续用Launch4J生成exe,确保JavaFX依赖被正确打包。可添加javafx-maven-plugin辅助处理:

    <plugin>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-maven-plugin</artifactId>
        <version>0.0.8</version>
        <configuration>
            <mainClass>com.novastream.NovastreamBackendApplication</mainClass>
        </configuration>
    </plugin>
    

验证

执行mvn clean package重新打包,运行java -jar target/novastream-backend-0.0.1-SNAPSHOT.jar,点击启动按钮确认服务正常启动。

内容的提问来源于stack exchange,提问作者Ishaan Vadhan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:17:01