【问题标题】:How to pass JVM options from bootRun如何从 bootRun 传递 JVM 选项
【发布时间】:2026-01-14 23:05:02
【问题描述】:

我正在开发与远程主机通信的简单 Spring Web 应用程序,我想在公司代理后面对其进行本地测试。 我使用“Spring Boot”gradle 插件,问题是如何为 JVM 指定代理设置?

我尝试了几种方法:

  1. gradle -Dhttp.proxyHost=X.X.X.X -Dhttp.proxyPort=8080 bootRun
  2. export JAVA_OPTS="-Dhttp.proxyHost=X.X.X.X -Dhttp.proxyPort=8080"
  3. export GRADLE_OPTS="-Dhttp.proxyHost=X.X.X.X -Dhttp.proxyPort=8080"

但似乎它们都不起作用 - “NoRouteToHostException”会引发“网络”代码。 另外,我添加了一些额外的代码来调试 JVM 启动参数:

    RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
    List<String> arguments = runtimeMxBean.getInputArguments();
    for (String arg: arguments) System.out.println(arg);

并且只打印了一个参数:“-Dfile.encoding=UTF-8”。

如果我在代码中设置系统属性:

    System.setProperty("http.proxyHost", "X.X.X.X");
    System.setProperty("http.proxyPort", "8080");

一切正常!

【问题讨论】:

    标签: java gradle spring-boot


    【解决方案1】:

    原始答案(使用 Gradle 1.12 和 Spring Boot 1.0.x):

    Spring Boot gradle 插件的bootRun 任务扩展了 gradle JavaExec 任务。见this

    这意味着您可以通过添加以下内容来配置插件以使用代理:

    bootRun {
       jvmArgs = "-Dhttp.proxyHost=xxxxxx", "-Dhttp.proxyPort=xxxxxx"
    }
    

    到您的构建文件。

    当然你可以用systemProperties代替jvmArgs

    如果您想从命令行有条件地添加 jvmArgs,您可以执行以下操作:

    bootRun {
        if ( project.hasProperty('jvmArgs') ) {
            jvmArgs project.jvmArgs.split('\\s+')
        }
    }
    
    gradle bootRun -PjvmArgs="-Dwhatever1=value1 -Dwhatever2=value2"
    

    更新答案:

    在使用 Spring Boot 1.2.6.RELEASEGradle 2.7 尝试了我上面的解决方案后,我发现它不像某些 cmets 提到的那样工作。 但是,可以进行一些小的调整来恢复工作状态。

    新代码是:

    bootRun {
       jvmArgs = ["-Dhttp.proxyHost=xxxxxx", "-Dhttp.proxyPort=xxxxxx"]
    }
    

    对于硬编码的参数,并且

    bootRun {
        if ( project.hasProperty('jvmArgs') ) {
            jvmArgs = (project.jvmArgs.split("\\s+") as List)
    
        }
    }
    

    从命令行提供的参数

    【讨论】:

    • 我不想在构建文件中“硬编码”这个选项。有可能指定代理设置会很棒。 IE。 - 使用命令行参数。
    • 不起作用:"> 无法在根项目上找到属性 'args'"。
    • 您是否正确复制了代码?我进行了更新。没有args 属性。
    • 我今天试过了,这项工作的唯一方法是用方括号括起来字符串列表,比如 bootRun { jvmArgs = ["-Dhttp.proxyHost=xxxxxx", "-Dhttp.proxyPort= xxxxxx"] }
    • 你用的是什么版本的gradle?
    【解决方案2】:
    bootRun {
      // support passing -Dsystem.property=value to bootRun task
      systemProperties = System.properties
    }
    

    这应该将所有 JVM 选项传递给通过 bootRun 启动的应用程序。

    【讨论】:

    • 这是迄今为止将命令行选项传递给 JVM 的最佳方式
    • @Marvin Frommhold,感谢您的回答。这种方法非常简单。对于像我这样的菜鸟,如果您添加更多细节会有所帮助。建议:(1)显示带有参数的gradle命令行调用; (2) 展示如何在 Spring Boot 中引用参数,例如 @Value("${property:default}"); (3) 传递参数的 IntelliJ 对话框的屏幕截图也会有所帮助。
    • 可悲的是,对我来说,只是添加它会导致 gradle bootRun 严重失败,并出现“org.apache.catalina.LifecycleException: A child container failed during start”,即使没有传递任何 -D 参数
    • 通过在*.com/questions/23689054的回答中挑选我想要的属性来解决
    【解决方案3】:

    在 gradle 构建脚本中,为运行任务定义 systemProperties。

    //to provide the properties while running the application using spring-boot's run task
        run {
            systemProperties['property name'] = 'value'
        }
    

    并且gradle run 应该接受这个值。

    或者定义一个项目级别的属性,如 http://forums.gradle.org/gradle/topics/how_can_i_provide_command_line_args_to_application_started_with_gradle_run

    【讨论】:

    • 是的,这个解决方案有效。但我不想让这段代码受源代码控制。我相信“最正确”的解决方案是直接在命令行中传递此选项。有什么办法吗?
    • 帖子中提到的链接有一种从命令行传递它们的方法
    • 你能说出它与使用 bootRun 相比如何吗?有什么不同吗?测试使用这个吗?类似的东西
    【解决方案4】:

    @marvin,感谢您的帖子,这对您很有帮助。

    分享我的使用方法:

    test {
      // support passing -Dsystem.property=value to bootRun task
      systemProperties = System.properties
    }
    

    我有想要跳过的 JUnit 测试,除非使用属性来包含此类测试。使用 JUnit Assume 有条件地包含测试:

    //first line of test
    assumeThat(Boolean.parseBoolean(System.getProperty("deep.test.run","false"),true)
    

    使用 gradle 执行此操作需要在运行 gradle build 时提供的系统属性,如下所示,

    gradle build -Ddeep.test.run=true
    

    确实通过了测试。

    希望这有助于其他人尝试这种方法来有条件地运行测试。

    【讨论】:

      【解决方案5】:
      bootRun {
        args = ['myProgramArgument1', 'myProgramArgument2']
      }
      

      使用 jvmArgs 可能会导致 JVM 启动问题。使用 args 允许您传递自定义程序参数

      【讨论】:

      • 你能告诉我如何在 Application.class 或 Bootstrap.class 中使用这些参数吗? (我正在使用 grails 3.x.x)
      【解决方案6】:

      它似乎有效:

      bootRun {
          systemProperties "property1": "value1", "property2": "value2"
      }
      

      【讨论】:

        【解决方案7】:

        我遇到了类似的问题,bootRun 需要一些参数,但我不想修改 bootRun,因为我想保持一些灵活性并坚持标准的 bootRun 行为。我的建议是添加一些扩展 bootRun 的自定义任务(比如说 bootRunDev、bootRunProxy),如下面的代码 sn-p 中所述

        task bootRunPxy(type: org.springframework.boot.gradle.run.BootRunTask, dependsOn: 'build') {
            group = 'Application'
            doFirst() {
                main = project.mainClassName
                classpath = sourceSets.main.runtimeClasspath
                systemProperty 'http.proxyHost', 'xxxxx'
                systemProperty 'http.proxyPort', 'yyyyy'
            }
        }
        

        我没有执行脚本的环境,但我使用此方法通过属性 spring.profiles.active 将配置文件传递给 spring。 学分应该去Karol Kaliński

        【讨论】:

          【解决方案8】:

          这里值得一提的是,一些使用 Gradle 和 Spring Boot 的系统在 build.gradle 之外启动 JVM,例如在 Dockerfile 中。

          在专门关于bootRun 的线程中提及这一点并非毫无意义!我之所以在这里结束,是因为这篇特别的帖子吸引了在 gradle 下编译/运行的 Spring Boot 应用程序上下文中搜索 jvm 选项的磁石。 (我发现添加 java.net.http.httpclient 日志记录的所有建议都说“将其添加到 bootRunjvmArgs”。但什么也没发生。

          因此,如果您碰巧从 Docker 容器运行 gradle 构建的 Spring Boot 应用程序,您需要将 JVM 参数添加到项目 Dockerfile 中的 env var 中,例如 -

          ...
          ENV JAVA_OPTS "${JAVA_OPTS} \
          -server \
          -Duser.timezone=UTC \
          -XX:InitialRAMPercentage=50 \
          -XX:MaxRAMPercentage=50 \
          -Djavax.net.ssl.trustStorePassword=elvislives \
          -Djavax.net.ssl.trustStoreProvider=BCFIPS \
          -Djavax.net.ssl.trustStoreType=BCFKS \
          -Djdk.internal.httpclient.debug=true \
          -Djava.util.logging.manager=org.apache.logging.log4j2.jul.LogManager \
          -Djdk.httpclient.HttpClient.log=errors,requests,headers,frames[:control:data:window:all..],content,ssl,trace,channel \
          "
          ...
          
          ENTRYPOINT java ${JAVA_OPTS} -cp app:app/lib/* com.mygreatcompany.theapp
          

          【讨论】:

          • 我来这里也是出于同样的原因,所以感谢您发布此信息。但是,如何将这种方法与gradle bootRun 任务结合起来?我想使用 bootRun 以便容器也将根据需要重新构建应用程序。