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

相关概念:gradle

在多模块 Gradle 项目里,库模块给业务模块使用,常见就两种方式:

  • 直接依赖兄弟模块
  • 先发布成 jar,再像普通依赖一样引用

项目内直接依赖

如果 app -> lib1 -> lib2 都在同一个仓库里,最直接的做法就是:

dependencies {
    implementation(project(":lib1"))
}

lib1 再决定自己怎样暴露 lib2

dependencies {
    api(project(":lib2"))
}

apiimplementation 的区别只记一件事

api 会把依赖继续暴露出去,implementation 不会。

也就是说:

  • lib1api(project(":lib2")),那 app 只依赖 lib1 就够了
  • lib1implementation(project(":lib2")),那 app 如果也要直接用 lib2 的类型,就得自己再显式依赖一次

这件事本质上不是语法选择,而是在声明:

lib2 到底是不是 lib1 对外 API 的一部分。

什么时候该发布成 jar

如果这个库不仅给当前仓库里的兄弟模块用,还要给别的项目复用,就更适合发布成制品。

Gradle 里最常见的是用 maven-publish

plugins {
    kotlin("jvm") version "1.9.20"
    `maven-publish`
}
 
group = "org.looko"
version = "0.0.1-SNAPSHOT"
 
publishing {
    publications {
        register(project.name, MavenPublication::class) {
            from(components["java"])
        }
    }
    repositories {
        mavenLocal()
    }
}

经验

在多模块项目里,先想清楚“模块边界”比先写依赖更重要:

  • 仅供内部实现使用的依赖,用 implementation
  • 需要被下游模块感知的类型,再用 api
  • 需要跨仓库复用时,再考虑发布到 Maven 仓库

边界一旦模糊,后面通常会变成“到处能依赖,但谁也说不清为什么能依赖”。