Gradle多模块应用构建可执行Jar遇主清单属性缺失问题
多模块Gradle项目构建可执行Jar的正确配置
问题核心
你遇到的两个关键问题:
- 构建的Jar缺失主清单属性:根项目全局的Jar配置未精准作用于主模块,且普通Jar未包含依赖类;
- 重复Entry错误:多模块构建时Kotlin生成的
*.kotlin_module文件重复,未配置重复处理策略。
解决步骤
1. 移除根项目全局Jar配置
删除根build.gradle中的这段全局配置——它会干扰所有模块的Jar构建逻辑:
tasks.withType(Jar) { duplicatesStrategy = DuplicatesStrategy.EXCLUDE manifest { attributes["Main-Class"] = "main.Main" } }
2. 单独配置主模块(:bot-app)
主模块是唯一需要可执行Jar的模块,在其build.gradle中选择以下方案之一:
方案一:使用Application插件(推荐)
Gradle原生的Application插件可自动处理主类配置、依赖打包,还能生成启动脚本:
plugins { id 'java' id 'kotlin' // 若使用Kotlin则添加 id 'application' } // 指定主类全路径 application { mainClass.set("main.Main") } // 处理重复文件 tasks.withType(Jar) { duplicatesStrategy = DuplicatesStrategy.EXCLUDE } // 可选:用Shadow插件生成单文件Fat Jar(需先引入插件) plugins { id 'com.github.johnrengelman.shadow' version '7.1.2' } shadowJar { manifest { attributes 'Main-Class': 'main.Main' } duplicatesStrategy = DuplicatesStrategy.EXCLUDE }
方案二:手动配置可执行Jar
若需自定义打包逻辑,可手动创建Jar任务:
plugins { id 'java' id 'kotlin' } // 自定义可执行Jar任务 task executableJar(type: Jar) { // 设置主清单属性 manifest { attributes["Main-Class"] = "main.Main" // 可选:配置类路径(若依赖未打包进Jar则需要) attributes["Class-Path"] = configurations.runtimeClasspath.files.collect { it.name }.join(' ') } // 打包当前模块的编译输出 from sourceSets.main.output // 打包所有依赖到Jar中(生成Fat Jar) from { configurations.runtimeClasspath.findAll { it.name.endsWith('.jar') }.collect { zipTree(it) } } // 处理重复文件 duplicatesStrategy = DuplicatesStrategy.EXCLUDE } // 让assemble任务依赖自定义Jar任务 assemble.dependsOn(executableJar)
3. 构建与运行
- Application插件方案:
执行./gradlew :bot-app:shadowJar(若用Shadow插件),生成的Fat Jar在bot-app/build/libs/目录下,命名格式为bot-app-<版本号>-all.jar; - 手动配置方案:
执行./gradlew :bot-app:executableJar,生成的Jar在bot-app/build/libs/目录下。
运行Jar:
java -jar bot-app/build/libs/[你的Jar文件名].jar
4. 彻底解决重复Entry问题
确保主模块中所有涉及Jar打包的任务(Jar、shadowJar等)都设置了duplicatesStrategy = DuplicatesStrategy.EXCLUDE,配置完成后无需频繁删除.gradle文件夹,构建会自动处理重复文件。
内容的提问来源于stack exchange,提问作者Roman Aymaletdinov
相关产品推荐
相关产品推荐

