跳至主要內容

解决 Gradle 父项目的 subprojects 中无法获取子项目属性的问题

Mr.Chen大约 3 分钟文章JavaGradle

概要

最近在折腾 Gradle 的依赖版本统一管理,真的是一步一个坑。一开始求助于 ChatGPT ,提供了两个插件,一个是 java-platform ,另一个是 io.spring.dependency-management 。我选择了使用 java-platform ,但是各种尝试都是报错,大家有兴趣可以看看官网例子。
https://docs.gradle.org/current/userguide/java_platform_plugin.htmlopen in new window

后来几番搜索,发现 Gradle7 之后又有一种新的版本管理的方式dependencyResolutionManagement,官网介绍如下。
https://docs.gradle.org/current/userguide/platforms.htmlopen in new window

但是官网的介绍太碎片化了,所以又百度了一下,找到了下面这个贴子,里面介绍得非常详细。
https://zhuanlan.zhihu.com/p/570009095?utm_id=0open in new window

主要内容

父项目 settings.gradle

rootProject.name = 'jia'

include 'jia-core', 'jia-mapper-common'

dependencyResolutionManagement {
    versionCatalogs {
        libs {
            library('slf4j.api', 'org.slf4j:slf4j-api:1.7.30')
            library('pagehelper', 'com.github.pagehelper:pagehelper:5.1.11')
            library('mybatis-plus-core', 'com.baomidou:mybatis-plus:3.3.0')
            library('jakarta.inject.api', 'jakarta.inject:jakarta.inject-api:2.0.1')
            library('swagger.annotations', 'io.swagger:swagger-annotations:1.5.20')
            library('lombok', 'org.projectlombok:lombok:1.18.20')
            library('log4j', 'log4j:log4j:1.2.17')
            library('slf4j-log4j12', 'org.slf4j:slf4j-log4j12:1.7.5')
        }
    }
}

父项目 build.gradle

allprojects {
    group = 'cn.jia'
}

subprojects {
    apply plugin: 'java-library'
    apply plugin: 'maven-publish'

    dependencies {
        implementation libs.slf4j.api
        annotationProcessor libs.lombok
        compileOnly libs.lombok
    }

    java.sourceCompatibility = JavaVersion.VERSION_17

    tasks.withType(JavaCompile).tap {
        configureEach {
            options.encoding = 'UTF-8'
        }
    }

    test {
        useJUnitPlatform()
    }

    processTestResources.dependsOn copyTestResources

    publishing {
        publications {
            mavenJava(MavenPublication) {
                from components.java
            }
        }
        repositories {
            maven {
                url = version.endsWith('SNAPSHOT') ? rootProject.ext.snapshotsRepoUrl : rootProject.ext.snapshotsRepoUrl
                credentials {
                    username rootProject.ext.repoUsername
                    password rootProject.ext.repoPassword
                }
            }
        }
    }
}

jia-core 项目的 build.gradle

dependencies {
    implementation libs.log4j
    implementation libs.slf4j.api
    implementation libs.slf4j.log4j12
    implementation libs.lombok
    testImplementation libs.junit.jupiter
    testAnnotationProcessor libs.lombok
    testImplementation libs.lombok
}
version = '1.1.1-SNAPSHOT'
description = 'jia-core'

jia-mapper-common 项目的 build.gradle

dependencies {
    api project(':jia-core')
    api libs.pagehelper
    api libs.mybatis.plus.core
    implementation libs.jakarta.inject.api
    api libs.swagger.annotations
}

version = '1.1.1-SNAPSHOT'
description = 'jia-mapper-common'

问题发现

配置完之后,项目能跑起来了,终于可以进行统一版本管理,不用每个模块单独去升级依赖。接着就是要将 jia-core 模块发布到maven私服上了,用的是阿里的私仓, RELEASE 仓和 SNAPSHOT 仓是分开的。这时候问题出现了,我当前版本是 1.1.1-SNAPSHOT ,应该上传到 SNAPSHOT 才对,但却上传到 RELEASE 仓去了。
那肯定是 url 不对,只能调试一下,所以加打印了一下url。

repositories {
    maven {
        println version
        url = version.endsWith('SNAPSHOT') ? rootProject.ext.snapshotsRepoUrl : rootProject.ext.snapshotsRepoUrl
        credentials {
            username rootProject.ext.repoUsername
            password rootProject.ext.repoPassword
        }
    }
}

发现输出的却是unspecified,明明 jia-core 项目的 build.gradle 中已经定义了 version ,但为什么就是识别不了。

问题解决

又是一轮各种尝试, Gradle 的指导文档真的很少,真心不想把 Gradle 官网翻一遍。
我分别在父项目的 allprojects 、 subprojects 、 ext 和子项目的 allprojects 、 subprojects 、 ext 中都加了定义了 version 。发现在父项目中定义的 version 都能识别到,而在子项目中定义的 version 都识别不到。
然后无意中看到一个贴子,说 Gradle 的加载顺序依次是父项目的 setting.gradle -> 父项目的 build.gradle -> 子项目的 build.gradle 。而 subprojects 是写在父项目的 build.gradle 上的,加载的时候还没加载子项目的 build.gradle ,自然是获取不了子项目的 version 。

其实官网也是有介绍的,只是英文实在不行,不容易理解。
https://docs.gradle.org/current/userguide/publishing_maven.html#publishing_maven:deferred_configurationopen in new window

既然知道原因,那就好办了,只要把 publishing 方法用 afterEvaluate 包起来即可,目的是加载完所有配置文件再加载 publishing 方法,自然就能获取得到 version 了。

allprojects {
    group = 'cn.jia'
}

subprojects {
    apply plugin: 'java-library'
    apply plugin: 'maven-publish'

    dependencies {
        implementation libs.slf4j.api
        annotationProcessor libs.lombok
        compileOnly libs.lombok
    }

    java.sourceCompatibility = JavaVersion.VERSION_17

    tasks.withType(JavaCompile).tap {
        configureEach {
            options.encoding = 'UTF-8'
        }
    }

    test {
        useJUnitPlatform()
    }

    processTestResources.dependsOn copyTestResources

    afterEvaluate {
        publishing {
            publications {
                mavenJava(MavenPublication) {
                    from components.java
                }
            }
            repositories {
                maven {
                    url = version.endsWith('SNAPSHOT') ? rootProject.ext.snapshotsRepoUrl : rootProject.ext.snapshotsRepoUrl
                    credentials {
                        username rootProject.ext.repoUsername
                        password rootProject.ext.repoPassword
                    }
                }
            }
        }
    }
}