多模块Gradle项目的库模块依赖方式

简而言之, 在 Gradle 管理的多模块项目中, 一个服务模块 (app/server) 引用必要的库模块 (lib) 主要有两种方式:

  1. 引用库模块项目本身
  2. 引用库模块打好的 jar 包

详细方式与案例见下文.

一 引用库模块项目本身

构建一个 demo, 我此处使用 Kotlin 写示例以便展示的代码足够简洁, 用 Java 或者其它 JVM 语言也是一样的

app 依赖 lib1, lib1 依赖 lib2, 目录结构如下:

shell 复制代码
gradle-subproject-demo
├── app
│   ├── build.gradle.kts
│   └── src
│       └── main
│           └── kotlin
│               └── org.looko.app
│                           └── App.kt
├── lib1
│   ├── build.gradle.kts
│   └── src
│       └── main
│           └── kotlin
│               └── org.looko.lib1
│                            └── util
│                              └── LogUtil.kt
├── lib2
│   ├── build.gradle.kts
│   └── src
│       └── main
│           └── kotlin
│               └── org.looko.lib2
│                           └── component
│                               └── MyLoggerComponent.kt
└── settings.gradle.kts

接下来在代码上达成 App.kt 依赖 LogUtil.kt 依赖 MyLoggerComponent.kt

根目录

主要是声明 rootProject 和子模块

如果是用 IDEA 的 New Mudule 创建的模块一般会自动生成不用修改

若没有则手动添加

settings.gradle.kts

kotlin 复制代码
plugins {
    // Apply the foojay-resolver plugin to allow automatic download of JDKs
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
}
rootProject.name = "gradle-subproject-demo"
include("app")
include("lib1")
include("lib2")

模块 lib2

build.gradle 不需要改

在代码中定义一个简单的日志实现以供给 lib1 使用

MyLoggerComponent.kt

kotlin 复制代码
package org.looko.lib2.component

import kotlin.reflect.KClass

interface MyLogger {
    fun info(msg: String)
}

class MyLoggerFactory {
    companion object {
        fun getLogger(clazz: KClass<*>): MyLogger =
            object : MyLogger {
                override fun info(msg: String) {
                    println("${clazz.simpleName} info: $msg")
                }
            }
    }
}

模块 lib1

build.gradle.kts 直接引用模块

kotlin 复制代码
dependencies {
    api(project(":lib2"))
    ...
}

注意: 此处使用 api 是带依赖传递的, 之后在 app 模块中只需引入依赖 lib1 即可; 如果使用 implementation 则后面的 app 模块不仅要引入依赖 lib1 还要引入依赖 lib2

使用 lib2 的内容, 定义一个全局都能用的 logger 以供 app 使用

LogUtil.kt

kotlin 复制代码
package org.looko.lib1.util

import org.looko.lib2.component.MyLogger
import org.looko.lib2.component.MyLoggerFactory

inline val Any.logger: MyLogger
    get() = MyLoggerFactory.getLogger(this::class)

模块 app

build.gradle.kts 直接引用模块

kotlin 复制代码
dependencies {
    implementation(project(":lib1"))
    ...
}

若是如上面所说 lib1 依赖 lib2 时用的是 implementation 而非 api , 则此处需要再写上 implementation(project(":lib2"))

在类中使用 lib1的内容

App.kt

kotlin 复制代码
package org.looko.app

import org.looko.lib1.util.logger

class App {
    val greeting: String
        get() {
            logger.info("success")
            return "Hello World!"
        }
}

fun main() {
    println(App().greeting)
}

运行后即可成功输出:

shell 复制代码
App info: success
Hello World!

二 引用库模块打好的 jar 包

如果这个库除了给同一项目的兄弟模块使用之外, 还想要给其它项目使用, 可以打成 jar 包到依赖仓库中

这便是大多数人习惯的通用的依赖管理方式了

在示例 Kotlin 项目中, 由于是使用 Gradle 作为构建工具, 同样可以使用 maven-publish 插件进行打包

比如 lib2 模块里的配置文件可以这么写

build.gradle.kts

kotlin 复制代码
plugins {
    kotlin("jvm") version "1.9.20"
    `maven-publish`
}

group = "org.looko"
version = "0.0.1-SNAPSHOT"

val sourcesJar by tasks.registering(Jar::class) {
    archiveClassifier.set("sources")
    from(sourceSets.main.get().allSource)
}

publishing {
    publications {
        register(project.name, MavenPublication::class) {
            groupId = project.group as String
            artifactId = project.name
            version = project.version as String
            from(components["java"])
            artifact(sourcesJar.get())
        }
    }
    repositories {
        maven {
            mavenLocal()
        }
    }
}

另外如果是 Spring Boot (Starter) 项目, 打出来的包可能会带 plain 后缀, 一些项目可能不识别, 可以在build.gradle.kts 下加如下任务:

kotlin 复制代码
// 将可执行 jar 包加以区分
tasks.named<BootJar>("bootJar") {
    archiveClassifier.set("boot")
}

// 清除 plain 后缀
tasks.named<Jar>("jar") {
    archiveClassifier.set("")
}

如果打出的包可以正常引用则不用加

总结

上述介绍了在 Gradle 多模块项目中的两种引用依赖的方式

两种方式均可以在普通 Libaray 类或者是 SpringBootStarter 类中使用

相关推荐
Kapaseker5 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
A0微声z2 天前
Kotlin Multiplatform (KMP) 中使用 Protobuf
kotlin
alexhilton3 天前
使用FunctionGemma进行设备端函数调用
android·kotlin·android jetpack
lhDream3 天前
Kotlin 开发者必看!JetBrains 开源 LLM 框架 Koog 快速上手指南(含示例)
kotlin
RdoZam3 天前
Android-封装基类Activity\Fragment,从0到1记录
android·kotlin
Kapaseker3 天前
研究表明,开发者对Kotlin集合的了解不到 20%
android·kotlin
糖猫猫cc4 天前
Kite:两种方式实现动态表名
java·kotlin·orm·kite
如此风景4 天前
kotlin协程学习小计
android·kotlin
Kapaseker4 天前
你搞得懂这 15 个 Android 架构问题吗
android·kotlin
zh_xuan4 天前
kotlin 高阶函数用法
开发语言·kotlin