1. 简介

本文将深入探讨如何通过 Gradle 执行 Java 的 main 方法。这是日常开发中非常常见的需求,比如运行测试程序、启动脚本或调试工具类。掌握几种不同的实现方式,能让你在不同场景下更灵活地选择方案,避免踩坑。

2. Java main 方法示例

我们先准备一个简单的 Java 类,用于演示各种运行方式:

public class MainClass {
    public static void main(String[] args) {
        System.out.println("Goodbye cruel world ...");
    }
}

这个类只有一个 main 方法,输出一句话。接下来我们会用 Gradle 的多种方式来执行它。

3. 使用 Application 插件(推荐新手)

Gradle 提供了一个开箱即用的 Application 插件,专门用于构建和运行可执行的 Java 应用。它会自动生成 run 任务,配置简单,适合快速上手。

build.gradle 中添加以下配置:

plugins {
    id "application"
}
apply plugin: "java" 

ext {
   javaMainClass = "com.baeldung.gradle.exec.MainClass"
}

application {
    mainClassName = javaMainClass
}

说明:

  • plugins { id "application" } 启用插件
  • mainClassName 指定入口类的全限定名(含包名)
  • ext 块用于定义公共变量,便于复用

配置完成后,直接运行:

./gradlew run

输出结果:

> Task :run
Goodbye cruel world ...

BUILD SUCCESSFUL in 531ms
2 actionable tasks: 1 executed, 1 up-to-date

⚠️ 注意: mainClassName 已被标记为过时,新版本建议使用 mainClass.set(...),但兼容性尚可,老项目无需急着改。

4. 使用 JavaExec 任务(灵活可控)

如果你不想引入 Application 插件,或者需要更细粒度控制 JVM 参数、环境变量等,可以使用 JavaExec 任务类型。

自定义任务如下:

task runWithJavaExec(type: JavaExec) {
    group = "Execution"
    description = "Run the main class with JavaExecTask"
    classpath = sourceSets.main.runtimeClasspath
    main = javaMainClass
}

关键点:

  • type: JavaExec 表示这是一个 JVM 进程执行任务
  • classpath 必须指定,通常使用 sourceSets.main.runtimeClasspath
  • main 设置主类全限定名
  • 可扩展添加 jvmArgs, args, systemProperties

执行命令:

./gradlew runWithJavaExec

输出:

> Task :runWithJavaExec
Goodbye cruel world ...

BUILD SUCCESSFUL in 526ms
2 actionable tasks: 1 executed, 1 up-to-date

💡 适用场景:

  • 需要传参给 main(String[] args)
  • 调整堆内存、GC 参数
  • 多个入口类切换运行

5. 使用 Exec 任务(底层控制)

Exec 是最底层的任务类型,直接调用操作系统命令。虽然灵活性最高,但也最易出错,需手动处理依赖和路径。

我们分三种情况来演示。

5.1. 从编译输出目录运行

先编译再执行 class 文件:

task runWithExec(type: Exec) {
    dependsOn build
    group = "Execution"
    description = "Run the main class with ExecTask"
    commandLine "java", "-classpath", sourceSets.main.runtimeClasspath.getAsPath(), javaMainClass
}

要点:

  • dependsOn build 确保先编译
  • commandLine 构造完整的 java -cp ... 命令
  • getAsPath() 将 classpath 转为字符串

执行:

./gradlew runWithExec

输出正常,耗时略长(因为触发了完整构建)。

5.2. 从普通 Jar 文件运行

打包成 jar 后运行,需显式指定主类:

task runWithExecJarOnClassPath(type: Exec) {
    dependsOn jar
    group = "Execution"
    description = "Run the mainClass from the output jar in classpath with ExecTask"
    commandLine "java", "-classpath", jar.archiveFile.get(), javaMainClass
}

⚠️ 注意:

  • jar.archiveFile.get() 获取 jar 文件路径
  • 依然是 -classpath 加主类方式,不是 -jar
  • 适用于没有设置 Main-Class 的 jar

执行成功后输出相同。

5.3. 从可执行 Jar 运行

生成带 Main-Class 的可执行 jar:

jar {
    manifest {
        attributes(
            "Main-Class": javaMainClass
        )
    }
}

task runWithExecJarExecutable(type: Exec) {
    dependsOn jar
    group = "Execution"
    description = "Run the output executable jar with ExecTask"
    commandLine "java", "-jar", jar.archiveFile.get()
}

优势:

  • 不需要指定 classpath
  • 命令简洁,符合生产部署习惯
  • manifest 中定义入口点

执行:

./gradlew runWithExecJarExecutable

输出一致,且命令更干净。

6. 总结与选型建议

方式 优点 缺点 推荐场景
✅ Application 插件 配置简单,开箱即用 灵活性低 快速原型、学习项目
✅ JavaExec 控制精细,无需插件 需手动配置 classpath 需要传参、调 JVM 参数
⚠️ Exec 完全自由,可执行任意命令 易出错,维护成本高 特殊集成、脚本化部署

📌 最终建议:

  • 日常开发首选 JavaExec,简单粗暴又灵活
  • 团队项目可用 Application 插件,统一规范
  • Exec 仅在必要时使用,比如要调外部脚本或特殊启动逻辑

示例代码已整理至 GitHub:https://github.com/baeldung/tutorials/tree/master/gradle-modules/gradle-5


原始标题:Run a Java main Method Using Gradle | Baeldung