1. 引言

本文将探索三种在构建时读取Gradle文件中定义变量的方法。当Java代码需要根据构建配置改变行为时,这个技巧特别实用——我们只需在Gradle中定义一次变量,避免在Java和Gradle中重复定义。我们将通过代码生成变量注入两种方式解决这个问题。

2. 生成Java类

首先定义Gradle变量:

ext {
   myVersion = '1.2.3'
}

通过构建时生成代码,能让Gradle变量在Java中访问

第一种方案是创建包含静态变量的final类。首先将生成目录加入编译路径:

def generatedDir = "$buildDir/generated-src"

sourceSets {
   main {
      java {
         srcDirs += "$generatedDir"
      }
   }
}

然后定义Gradle任务生成BuildConfig.java文件:

tasks.register('generateBuildConfig') {
   doLast {
      def outputDir = file("$generatedDir/com/baeldung/gradle/config")
      outputDir.mkdirs()
      def file = new File(outputDir, "BuildConfig.java")
      file.text = """
         package com.baeldung.gradle.config;

         public final class BuildConfig {
            public static final String MY_VERSION = "${myVersion}";
            private BuildConfig() {}
         }
      """.stripIndent()
   }
}

这个文件可以包含任意数量变量——这里我们只读取预定义的myVersion。执行generateBuildConfig任务后,将在build/generated-src/com/baeldung/gradle/config目录生成:

package com.baeldung.gradle.config;

public final class BuildConfig {
   public static final String MY_VERSION = "1.2.3";
   private BuildConfig() {}
}

由于已将generated-src加入项目源路径,可直接通过静态成员访问:

assertEquals("1.2.3", BuildConfig.MY_VERSION);

最后将任务加入构建流程:

compileJava.dependsOn generateBuildConfig

这样确保compileJavagenerateBuildConfig之后执行。

3. 生成属性文件

第二种方案是构建时生成properties文件。这种方法与上一种类似,但输出和读取方式不同。

首先将生成目录加入资源路径:

def generatedResourcesDir = "$buildDir/generated-resources"

sourceSets {
   main {
      resources {
         srcDirs += "$generatedResourcesDir"
      }
   }
}

然后定义generateProperties任务:

tasks.register('generateProperties') {
   doLast {
      def mainResourcesDir = file("$generatedResourcesDir/main")
      mainResourcesDir.mkdirs()
      def mainFile = file("$mainResourcesDir/version.properties")
      mainFile.text = "MY_VERSION=${myVersion}"
   }
}

此任务在build/generated-resources/main目录生成version.properties文件:

MY_VERSION=1.2.3

使用Properties类读取文件:

Properties props = new Properties();
props.load(Thread.currentThread()
  .getContextClassLoader()
  .getResourceAsStream("version.properties"));
String version = props.getProperty("MY_VERSION");
assertEquals("1.2.3", version);

同样需要设置任务依赖:

compileJava.dependsOn generateProperties

确保generatePropertiescompileJava前执行。

4. 注入为环境或系统属性

⚠️ 最简单粗暴的方法:注入为环境或系统属性。需要为特定任务指定注入变量。

test任务为例:

test {
   systemProperty "MY_VERSION", "${myVersion}"
   environment "MY_VERSION", "${myVersion}"
}

其他任务(如bootRun)同样适用。读取方式极其简单:

assertEquals("1.2.3", System.getProperty("MY_VERSION"));
assertEquals("1.2.3", System.getenv("MY_VERSION"));

无需调整任务执行顺序,这是此方案的优势。

5. 总结

本文讨论了三种在Java中读取Gradle变量的方法,各有适用场景:

  • 常量代码生成:编译时检查,减少运行时错误
  • 属性文件生成:适合资源类配置
  • 运行时注入:最动态的方案,理论上无需重启应用即可更新变量值

⚠️ 踩坑提示:选择方案时需权衡编译安全性和运行时灵活性需求。生产环境推荐前两种方案,开发调试可用第三种。

完整示例代码见GitHub仓库