如何将Gradle子项目的source set输出合并到其他子项目Jar中?
问题场景与优化方案
项目结构
三个子项目均使用java-library插件,根项目仅通过allprojects块设置group和version信息:
Root project 'project' +--- Project ':project-a' +--- Project ':project-b' +--- Project ':project-c'
依赖关系
project-a无依赖project-c通过api(project(":project-a"))依赖project-aproject-b通过api(project(":project-c"))依赖project-c(间接依赖project-a)
需求
- 构建
project-c时,生成的Jar需包含project(":project-a").sourceSets["main"].output的所有类 - 构建
project-b时,生成的Jar需包含project(":project-a").sourceSets["main"].output和project(":project-c").sourceSets["main"].output的所有类
已尝试方案
在根项目build.gradle.kts中添加:
project(":project-c").evaluationDependsOn(":project-a") project(":project-b").evaluationDependsOn(":project-c")
并分别在project-c和project-b的build.gradle.kts中配置:
// project-c/build.gradle.kts tasks.jar { from(project(":project-a").sourceSets["main"].output) }
// project-b/build.gradle.kts tasks.jar { from(project(":project-a").sourceSets["main"].output) from(project(":project-c").sourceSets["main"].output) }
该方案可行但不够优雅,希望通过Gradle配置实现更优方案。
补充: 经查阅资料,若懒加载配置jar任务,无需调用evaluationDependsOn。
更优解决方案
方案1:懒加载配置Jar任务(消除evaluationDependsOn)
利用Gradle的懒加载特性,通过provider延迟解析依赖项目的sourceSets,无需手动指定项目评估顺序,代码更简洁且符合Gradle最佳实践:
project-c/build.gradle.kts 配置:
tasks.jar { // 懒加载获取project-a的main输出,任务执行阶段才解析 from(provider { project(":project-a").sourceSets.main.get().output }) }
project-b/build.gradle.kts 配置:
tasks.jar { from(provider { project(":project-a").sourceSets.main.get().output }) from(provider { project(":project-c").sourceSets.main.get().output }) }
方案2:使用Shadow插件(规范的Fat Jar构建)
如果需要更灵活的打包控制(比如重复类处理、资源合并),可以使用官方推荐的com.github.johnrengelman.shadow插件,它是Gradle生态中成熟的Fat Jar构建工具:
- 根项目引入插件:
plugins { id("com.github.johnrengelman.shadow") version "8.1.1" apply false }
- project-c/build.gradle.kts 配置:
plugins { id("java-library") id("com.github.johnrengelman.shadow") } shadowJar { from(project(":project-a").sourceSets.main.get().output) classifier = "" // 去掉默认的"-all"后缀,替代默认jar输出 } // 让build任务自动触发shadowJar tasks.build { dependsOn(tasks.shadowJar) }
- project-b/build.gradle.kts 配置:
plugins { id("java-library") id("com.github.johnrengelman.shadow") } shadowJar { from(project(":project-a").sourceSets.main.get().output) from(project(":project-c").sourceSets.main.get().output) classifier = "" } tasks.build { dependsOn(tasks.shadowJar) }
方案3:自定义配置管理嵌入项目
如果不想依赖第三方插件,可通过自定义配置统一管理需要嵌入的项目,后续维护更便捷:
project-c/build.gradle.kts 配置:
// 定义自定义配置,用于管理需要嵌入的项目 val embeddedProjects by configurations.creating { isCanBeConsumed = false isCanBeResolved = false } dependencies { embeddedProjects(project(":project-a")) } tasks.jar { // 遍历配置中的项目,获取其main输出 from(embeddedProjects.map { project(it.name).sourceSets.main.get().output }) }
project-b/build.gradle.kts 配置:
val embeddedProjects by configurations.creating { isCanBeConsumed = false isCanBeResolved = false } dependencies { embeddedProjects(project(":project-a")) embeddedProjects(project(":project-c")) } tasks.jar { from(embeddedProjects.map { project(it.name).sourceSets.main.get().output }) }
内容的提问来源于stack exchange,提问作者Alex R
相关产品推荐
相关产品推荐

