1. 概述
在使用 Gradle 构建项目时,我们经常需要执行一些外部程序或 Java 主类,而这些程序往往依赖命令行参数来控制行为。比如指定环境、传入配置项,甚至动态开启某些功能。
本文将带你掌握如何在 Gradle 中正确地向 Java 应用或其他外部命令传递命令行参数,避免踩坑。✅
2. 输入参数的类型
从 Gradle 命令行传参,主要有两种方式:
- 使用
-D
设置 JVM 系统属性(System Properties) - 使用
-P
设置 项目属性(Project Properties)
⚠️ 关键区别:
类型 | 设置方式 | 读取方式 | 未定义时行为 |
---|---|---|---|
Project Property | -Pkey=value |
project.hasProperty("key") + project.getProperty("key") |
❌ 抛出 MissingPropertyException |
System Property | -Dkey=value |
System.getProperty("key") |
✅ 返回 null |
📌 最佳实践建议:除非你要调整 JVM 参数(如 -Dfile.encoding=UTF-8
),否则一律优先使用 -P
传参。
虽然也能用 -D
来传业务参数,但容易和 JVM 自身配置混淆,后期维护容易翻车。
来看一个例子,在 build.gradle
中定义任务:
apply plugin: "java"
description = "Gradle Command Line Arguments examples"
task propertyTypes() {
doLast {
if (project.hasProperty("args")) {
println "Our input argument with project property [" + project.getProperty("args") + "]"
}
println "Our input argument with system property [" + System.getProperty("args") + "]"
}
}
运行命令:
$ ./gradlew propertyTypes -Dargs=lorem -Pargs=ipsum
> Task :cmd-line-args:propertyTypes
Our input argument with project property [ipsum]
Our input argument with system property [lorem]
结果一目了然:-P
影响的是 Gradle 项目属性,-D
影响的是 JVM 层面的系统属性。
3. 向程序传递命令行参数
光读到参数还不够,关键是把它们传给目标程序。下面分场景说明。
3.1 向 Java 应用传递参数
方式一:使用 Application 插件(推荐,简单粗暴)
如果你的项目用了 application
插件,Gradle 提供了一个非常方便的 --args
参数。
先配置 build.gradle
:
apply plugin: "java"
apply plugin: "application"
description = "Gradle Command Line Arguments examples"
ext.javaMainClass = "com.baeldung.cmd.MainClass"
application {
mainClassName = javaMainClass
}
Java 主类示例:
public class MainClass {
public static void main(String[] args) {
System.out.println("Gradle command line arguments example");
for (String arg : args) {
System.out.println("Got argument [" + arg + "]");
}
}
}
运行时直接加 --args
:
$ ./gradlew :cmd-line-args:run --args="lorem ipsum dolor"
> Task :cmd-line-args:run
Gradle command line arguments example
Got argument [lorem]
Got argument [ipsum]
Got argument [dolor]
✅ 优点:简洁明了,适合大多数场景。
⚠️ 注意:--args
支持从 Gradle 4.9 开始,老版本不支持。
方式二:自定义 JavaExec 任务(灵活可控)
如果需要更精细控制(比如不同环境传不同参数),可以手写 JavaExec
任务。
ext.javaMainClass = "com.baeldung.cmd.MainClass"
if (project.hasProperty("args")) {
ext.cmdargs = project.getProperty("args")
} else {
ext.cmdargs = ""
}
task cmdLineJavaExec(type: JavaExec) {
group = "Execution"
description = "Run the main class with JavaExecTask"
classpath = sourceSets.main.runtimeClasspath
main = javaMainClass
args cmdargs.split()
}
运行命令:
$ ./gradlew cmdLineJavaExec -Pargs="lorem ipsum dolor"
> Task :cmd-line-args:cmdLineJavaExec
Gradle command line arguments example
Got argument [lorem]
Got argument [ipsum]
Got argument [dolor]
💡 技巧:args cmdargs.split()
会按空格拆分字符串成数组,自动处理多个参数。
⚠️ 踩坑提醒:别忘了
split()
,否则整个字符串会被当作一个参数传进去!
3.2 向外部程序传递参数
有时候你想调用 shell 命令、Python 脚本或其他可执行文件,这时候可以用 Gradle 的 Exec
任务。
if (project.hasProperty("args")) {
ext.cmdargs = project.getProperty("args")
} else {
ext.cmdargs = "ls"
}
task cmdLineExec(type: Exec) {
group = "Execution"
description = "Run an external program with ExecTask"
commandLine cmdargs.split()
}
比如运行 ls -ll
:
$ ./gradlew cmdLineExec -Pargs="ls -ll"
> Task :cmd-line-args:cmdLineExec
total 4
drwxr-xr-x 1 user 1049089 0 Sep 1 17:59 bin
drwxr-xr-x 1 user 1049089 0 Sep 1 18:30 build
-rw-r--r-- 1 user 1049089 1016 Sep 3 15:32 build.gradle
drwxr-xr-x 1 user 1049089 0 Sep 1 17:52 src
✅ 这种方式特别适合写 CI/CD 脚本,动态执行命令,避免硬编码。
💡 提示:
commandLine
接收的是字符串数组,所以split()
是关键,否则命令会被整体当作程序名。
4. 总结
场景 | 推荐方式 | 示例 |
---|---|---|
执行 Java 主类(简单) | application 插件 + --args |
./gradlew run --args="dev port=8080" |
执行 Java 主类(复杂) | 自定义 JavaExec 任务 |
args project.getProperty('args').split() |
执行外部命令 | Exec 任务 |
commandLine 'python', 'script.py', 'arg1' |
参数传递 | 优先使用 -P |
-Penv=prod -Pdebug=true |
📌 核心要点:
- ✅ 优先使用
-P
传项目属性,清晰且安全 - ✅
--args
是application
插件的语法糖,方便但有版本限制 - ✅
JavaExec
和Exec
提供最大灵活性,适合封装通用任务 - ❌ 避免滥用
-D
来传业务参数,容易引发歧义
完整代码示例已上传至 GitHub:https://github.com/baeldung/tutorials/tree/master/gradle-modules/gradle-5/cmd-line-args