0

0

Gradle项目创建包含依赖的Uber JAR并解决Kotlin库冲突

霞舞

霞舞

发布时间:2025-09-27 22:49:17

|

968人浏览过

|

来源于php中文网

原创

gradle项目创建包含依赖的uber jar并解决kotlin库冲突

本文详细介绍了如何在Gradle Kotlin项目中创建包含所有依赖的Uber JAR(也称作“胖JAR”),并着重解决在集成此类JAR时可能遇到的Kotlin运行时库冲突问题。通过使用com.github.johnrengelman.shadow插件,并配置其排除特定Kotlin库,可以确保生成的JAR文件在其他项目中被正确识别和使用,避免IDE无法解析类的问题。

1. 理解Uber JAR及其必要性

软件开发中,尤其是在需要将一个项目(例如一个库或微服务)打包成一个独立的可执行文件或易于分发的组件时,我们常常需要创建一个包含所有运行时依赖项的JAR文件,这被称为“Uber JAR”或“胖JAR”。这种打包方式简化了部署,因为所有必需的第三方库都被打包在同一个JAR中,无需额外管理依赖。

然而,简单地通过Gradle的jar任务来合并依赖通常不足以应对复杂场景,例如处理资源文件冲突或更深层次的依赖树。更重要的是,在Kotlin项目中,如果Uber JAR包含了Kotlin运行时库,当这个JAR被另一个同样使用Kotlin的项目引用时,可能会因为类路径上存在重复或不同版本的Kotlin运行时库而导致冲突,从而出现IDE无法识别JAR内部类或运行时错误。

2. 使用Shadow Plugin创建Uber JAR

com.github.johnrengelman.shadow插件是Gradle生态系统中创建Uber JAR的推荐解决方案。它能够智能地处理依赖项的合并,包括重命名包以避免冲突(Shading)以及处理资源文件。

初始配置 (Project A - 待打包项目):

首先,在你的Kotlin项目(例如Project A)的build.gradle.kts文件中,添加Shadow插件:

plugins {
    kotlin("jvm") version "1.6.21" // 使用你的Kotlin版本
    java // 确保java插件也已应用,shadow插件依赖它
    id("com.github.johnrengelman.shadow") version "7.1.2" // 使用最新稳定版本
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    // 你的项目依赖,例如
    implementation("org.mybatis.dynamic-sql:mybatis-dynamic-sql:1.4.1")
    testImplementation(kotlin("test"))
}

tasks.test {
    useJUnitPlatform()
}

tasks.withType {
    kotlinOptions.jvmTarget = "1.8"
}

// 配置assemble任务,使其依赖于shadowJar任务
tasks.assemble {
    dependsOn("shadowJar")
}

应用此配置后,运行gradle shadowJar命令将会在build/libs目录下生成一个名为your-project-name-version-all.jar(或类似名称)的Uber JAR,其中包含了所有运行时依赖。

3. 解决Kotlin库冲突问题

当Project A生成的Uber JAR包含Kotlin运行时库,并且被另一个Kotlin项目(例如Project B)引用时,IDE(如IntelliJ IDEA)可能会出现无法识别JAR内部类的问题。这通常是因为Project B本身已经通过其Kotlin插件引入了Kotlin运行时库,导致类路径上存在重复的Kotlin核心类。

为了解决这个问题,我们需要在创建Uber JAR时,明确地将Kotlin运行时相关的依赖从最终的JAR文件中排除。这样,当Project B引用这个Uber JAR时,它将使用自己已有的Kotlin运行时库,避免冲突。

百度MCP广场
百度MCP广场

探索海量可用的MCP Servers

下载

排除Kotlin库的Shadow Plugin配置 (Project A - 修正版):

在Project A的build.gradle.kts中,添加ShadowJar任务的配置,以排除所有以"kotlin"开头的依赖:

plugins {
    kotlin("jvm") version "1.6.21"
    java
    id("com.github.johnrengelman.shadow") version "7.1.2"
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

tasks.assemble {
    dependsOn("shadowJar")
}

// 关键步骤:配置ShadowJar任务以排除Kotlin库
tasks.withType {
    exclude {
        // 排除所有以"kotlin"开头的依赖,例如kotlin-stdlib, kotlin-reflect等
        it.name.startsWith("kotlin")
    }
    // 可以根据需要添加其他排除规则,例如:
    // exclude("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA") // 排除签名文件
}

dependencies {
    implementation("org.mybatis.dynamic-sql:mybatis-dynamic-sql:1.4.1")
    testImplementation(kotlin("test"))
}

tasks.test {
    useJUnitPlatform()
}

tasks.withType {
    kotlinOptions.jvmTarget = "1.8"
}

tasks.withType {
    // 保持为空或根据需要配置
}

通过exclude { it.name.startsWith("kotlin") }这行配置,Shadow插件在打包时会忽略所有名称以"kotlin"开头的JAR文件,这些通常是Kotlin的标准库、反射库等运行时依赖。重新运行gradle shadowJar后,生成的Uber JAR将不再包含这些Kotlin运行时库。

4. 在其他项目中使用Uber JAR (Project B)

一旦Project A生成了不含内部Kotlin运行时库的Uber JAR(例如ProjectA-1.0-SNAPSHOT-all.jar),Project B就可以将其作为本地文件依赖进行引用。

Project B 的 build.gradle.kts 配置:

plugins {
    kotlin("jvm") version "1.6.21"
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    // 引用Project A生成的Uber JAR
    // 假设JAR文件位于Project B的src/main/resources目录下
    implementation(files("src/main/resources/ProjectA-1.0-SNAPSHOT-all.jar"))
    testImplementation(kotlin("test"))
}

tasks.test {
    useJUnitPlatform()
}

tasks.withType {
    kotlinOptions.jvmTarget = "1.8"
}

此时,Project B的IDE应该能够正确识别ProjectA-1.0-SNAPSHOT-all.jar中的所有类,并且由于Kotlin运行时库由Project B自身提供,不会发生冲突。

5. 注意事项与最佳实践

  • 版本兼容性: 确保Project A(原始项目)和Project B(引用项目)使用的Kotlin版本兼容。如果Project B使用的Kotlin版本与Project A编译时使用的Kotlin版本差异过大,即使排除了Kotlin运行时库,也可能导致运行时问题。
  • 资源冲突: Shadow插件在合并JAR时会智能处理资源文件,但极端情况下仍需注意。如果两个依赖包含相同路径的资源文件,Shadow插件默认会选择第一个遇到的。
  • 发布到Maven仓库: 对于更专业的项目间依赖管理,最佳实践是将Project A发布到本地或远程Maven仓库,而不是直接引用本地JAR文件。这样Project B可以通过标准的Maven/Gradle依赖声明来引用Project A,Gradle会自动处理依赖的传递性。
  • 为什么不直接使用Gradle的jar任务合并依赖? Gradle的默认jar任务主要用于打包项目的类和资源,不直接处理其传递性依赖。虽然可以通过from(configurations.runtimeClasspath.get().map { zipTree(it) })手动合并,但这通常无法解决类路径冲突、资源文件冲突等复杂问题,而Shadow插件正是为此而生。

总结

创建包含所有依赖的Uber JAR是分发和部署Kotlin/Gradle项目的常见需求。com.github.johnrengelman.shadow插件提供了强大的功能来完成这项任务。然而,在Kotlin项目中,为了避免IDE无法识别类或运行时冲突,务必配置ShadowJar任务以排除Kotlin运行时相关的库。通过这种方式,可以确保生成的Uber JAR在其他Kotlin项目中能够无缝集成和正常运行。

相关专题

更多
Java Maven专题
Java Maven专题

本专题聚焦 Java 主流构建工具 Maven 的学习与应用,系统讲解项目结构、依赖管理、插件使用、生命周期与多模块项目配置。通过企业管理系统、Web 应用与微服务项目实战,帮助学员全面掌握 Maven 在 Java 项目构建与团队协作中的核心技能。

0

2025.09.15

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

75

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

36

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

59

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

38

2025.11.27

idea快捷键大全
idea快捷键大全

本专题为大家提供idea快捷键相关的文章,帮助大家解决问题。

164

2023.08.03

idea如何集成Tomcat
idea如何集成Tomcat

idea集成Tomcat的步骤:1、添加Tomcat服务器配置;2、配置项目部署;3、运行Tomcat服务器;4、访问项目;5、注意事项;6、关闭Tomcat服务器。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

167

2024.02.23

idea怎么配置maven
idea怎么配置maven

idea配置maven的步骤:1、打开intellij idea,并确保已安装maven integration插件,可以在"file"菜单中选择"settings",然后在"plugins"选项卡中搜索并安装maven integration插件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

119

2024.02.23

PHP WebSocket 实时通信开发
PHP WebSocket 实时通信开发

本专题系统讲解 PHP 在实时通信与长连接场景中的应用实践,涵盖 WebSocket 协议原理、服务端连接管理、消息推送机制、心跳检测、断线重连以及与前端的实时交互实现。通过聊天系统、实时通知等案例,帮助开发者掌握 使用 PHP 构建实时通信与推送服务的完整开发流程,适用于即时消息与高互动性应用场景。

11

2026.01.19

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.7万人学习

C# 教程
C# 教程

共94课时 | 7万人学习

Java 教程
Java 教程

共578课时 | 47.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号