3 个互动演示帮你理解 Plugin、Convention Plugin、buildSrc vs build-logic 的差异。
有 5 个子模块,每个都需要:JDK 17、JUnit 5、UTF-8 编码、统一仓库。看看用 / 不用 Convention Plugin 的差距。
// app/build.gradle.kts
plugins { java }
java { toolchain { languageVersion = JavaLanguageVersion.of(17) } }
repositories { mavenCentral() }
dependencies { testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") }
tasks.test { useJUnitPlatform() }
tasks.withType<JavaCompile>().configureEach { options.encoding = "UTF-8" }
// lib-core/build.gradle.kts —— 完全一样
plugins { java }
java { toolchain { languageVersion = JavaLanguageVersion.of(17) } }
repositories { mavenCentral() }
dependencies { testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") }
tasks.test { useJUnitPlatform() }
tasks.withType<JavaCompile>().configureEach { options.encoding = "UTF-8" }
// lib-data/build.gradle.kts —— 又一样
... (再 12 行)
// feature-billing/build.gradle.kts
... (再 12 行)
// feature-payment/build.gradle.kts
... (再 12 行)
// buildSrc/src/main/kotlin/my-java-conventions.gradle.kts
plugins { java }
java { toolchain { languageVersion = JavaLanguageVersion.of(17) } }
repositories { mavenCentral() }
dependencies { "testImplementation"("org.junit.jupiter:junit-jupiter:5.10.0") }
tasks.named<Test>("test") { useJUnitPlatform() }
tasks.withType<JavaCompile>().configureEach { options.encoding = "UTF-8" }
// app/build.gradle.kts —— 一行
plugins { id("my-java-conventions") }
// lib-core/build.gradle.kts
plugins { id("my-java-conventions") }
// lib-data/build.gradle.kts
plugins { id("my-java-conventions") }
// feature-billing/build.gradle.kts
plugins { id("my-java-conventions") }
// feature-payment/build.gradle.kts
plugins { id("my-java-conventions") }
💡 Convention Plugin 的本质:把"项目通用配置"抽出来 = DRY 原则在 Gradle 上的体现。当模块数 ≥ 3,强烈建议用。
需要 Plugin 吗?
├── 单项目内复用?
│ ├── 学习 / 小项目 → buildSrc
│ └── 生产 / 大项目 → build-logic(推荐)
└── 跨项目复用?
├── 公司内部 → 独立项目 + 发到公司 Nexus
└── 全球开源 → 独立项目 + 发到 Plugin Portal
同一个目的:"给项目应用一组配置 + 加一个 task",两种写法对比。
// buildSrc/src/main/kotlin/
// my-java-conv.gradle.kts
plugins {
java
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories { mavenCentral() }
dependencies {
"testImplementation"("org.junit.jupiter:junit-jupiter:5.10.0")
}
tasks.named<Test>("test") { useJUnitPlatform() }
tasks.register("hello") {
doLast { println("Hello from script plugin!") }
}
// build-logic/convention/src/main/kotlin/
// com/example/JavaConvPlugin.kt
class JavaConvPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("java")
extensions.configure<JavaPluginExtension>("java") {
toolchain.languageVersion.set(JavaLanguageVersion.of(17))
}
repositories.mavenCentral()
dependencies.add("testImplementation",
"org.junit.jupiter:junit-jupiter:5.10.0")
tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
tasks.register("hello") {
doLast { println("Hello!") }
}
}
}
}
// build-logic/convention/build.gradle.kts
gradlePlugin {
plugins {
register("javaConv") {
id = "my.java-conv"
implementationClass = "com.example.JavaConvPlugin"
}
}
}