使用jpackage打包Kotlin-Compose-Spring应用时主类找不到问题求助
问题分析与解决方案
问题描述
开发Kotlin-Compose-Spring独立应用,为Windows平台制作带JRE的安装包,但使用jpackage打包后,运行Jar或Exe时出现主类找不到错误:
Error: Could not find or load main class com.tfra.mechanic_management.MechanicManagementApplicationKt Caused by: java.lang.ClassNotFoundException: com.tfra.mechanic_management.MechanicManagementApplicationKt
同时生成的Exe本地无法正常运行,仅能在Windows Sandbox执行,否则需通过任务管理器终止。
错误原因及修复步骤
1. BootJar任务配置错误
Spring Boot的bootJar默认已生成包含所有依赖的可执行Fat Jar,你手动添加runtimeClasspath依赖的逻辑会导致Jar结构混乱,主类无法被正确识别。
修改BootJar任务配置:
tasks.named<org.springframework.boot.gradle.tasks.bundling.BootJar>("bootJar") { archiveFileName.set("${appName}-${version}.jar") manifest { attributes["Main-Class"] = "com.tfra.mechanic_management.MechanicManagementApplicationKt" } // 移除手动打包依赖的代码,bootJar已自动处理依赖打包 }
2. jlink生成Runtime Image时的模块路径错误
你将build/libs加入jlink的module-path,但Spring Boot应用是非模块化的,这会导致Runtime Image引入不必要的内容,甚至缺少必要模块。
修改generateRuntimeImage任务:
tasks.register<Exec>("generateRuntimeImage") { group = "build" description = "Generates a custom runtime image" val runtimeDir = layout.buildDirectory.dir("my-runtime").get().asFile doFirst { if (runtimeDir.exists()) { runtimeDir.deleteRecursively() } } commandLine( "jlink", "--module-path", "${System.getProperty("java.home")}/jmods", "--add-modules", "java.base,java.desktop,java.sql,java.naming,java.logging,java.management", "--output", runtimeDir.absolutePath, "--strip-debug", "--no-man-pages", "--no-header-files" ) }
3. jpackage的main-jar参数错误
--input已指定为build/libs,--main-jar只需填写Jar文件名,无需绝对路径,否则jpackage无法正确定位Jar内的主类。
修改createInstaller任务的commandLine部分:
commandLine( "$javaHome/bin/jpackage", "--type", "exe", "--input", "build/libs", "--main-jar", "${appName}-${version}.jar", // 仅填Jar文件名 "--name", appName, "--main-class", "com.tfra.mechanic_management.MechanicManagementApplicationKt", "--dest", outputDir, "--app-version", version.toString(), "--icon", "src/main/resources/car_icon.ico", "--java-options", "-Djava.awt.headless=false", "--java-options", "-Dlogging.file=app.log", "--resource-dir", "src/main/resources", "--runtime-image", layout.buildDirectory.dir("my-runtime").get().asFile.absolutePath )
4. 应用启动逻辑优化
Compose的application函数是阻塞式的,需确保Spring Boot上下文在关闭时正确销毁,避免进程残留导致假死:
修改主类启动代码:
@SpringBootApplication @EnableJpaRepositories(basePackages = ["com.tfra.mechanic_management.repository.jpa"]) @EntityScan(basePackages = ["com.tfra.mechanic_management.repository.entity"]) @ComponentScan(basePackages = ["com.tfra"]) class MechanicManagementApplication fun main(args: Array<String>) { val context = runApplication<MechanicManagementApplication>(*args) application { Window( onCloseRequest = { // 关闭Spring Boot上下文 context.close() exitApplication() }, title = "Mechanic Management" ) { MaterialTheme { AppUI(context) } } } }
5. 验证Jar文件结构
打包后解压生成的Jar文件,确认com/tfra/mechanic_management/MechanicManagementApplicationKt.class存在,确保主类被正确编译打包。
额外注意事项
- 确保使用Java 17的JDK执行jlink和jpackage,与项目toolchain版本一致
- 检查本地Windows环境是否有其他Java进程或依赖冲突,可尝试清理build目录后重新打包
内容的提问来源于stack exchange,提问作者TechGuy
相关产品推荐
相关产品推荐

