如何从bootRun传递JVM选项

121

我正在开发一个简单的Spring Web应用程序,它与远程主机通信,我想在公司代理后面本地测试它。

我尝试了几种方法:

  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"

但似乎它们都不起作用——"network"代码中会抛出"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");

一切都很顺利!

10个回答

132

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

Spring Boot Gradle插件的bootRun任务扩展了Gradle JavaExec任务。请参见此处

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

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进行上述解决方案后,我发现它并不像一些评论中提到的那样有效。然而,可以进行一些微小的调整以恢复工作状态。

新代码如下:

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

对于硬编码的参数,以及

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

    }
}

用于从命令行提供的参数


5
我希望您不要在构建文件中“硬编码”这些选项。最好能够指定代理设置的可能性,例如使用命令行参数。 - Evgeny
7
我今天尝试了一下,唯一可行的办法是用方括号将字符串列表包围起来,例如:bootRun { jvmArgs = ["-Dhttp.proxyHost=xxxxxx", "-Dhttp.proxyPort=xxxxxx"] } - Valentino Dell'Aica
你正在使用哪个版本的Gradle? - geoand
@AdamArold 你使用的是哪个版本的 Gradle? - geoand
@AdamArold,请查看我的更新答案,适用于最新版本的Spring Boot和Gradle。 - geoand
显示剩余13条评论

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

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


3
这绝对是将命令行选项传递给JVM的最佳方式。 - anubhava
1
@Marvin Frommhold,感谢您的回答。这种方法非常简单明了。对于像我这样的新手来说,如果您能添加更多细节,那将会很有帮助。建议:(1)展示gradle命令行调用及其参数;(2)展示如何在Spring Boot中引用参数,例如@Value("${property:default}");(3)IntelliJ对话框传递参数的截图也会很有帮助。 - Brett
1
遗憾的是,对我来说,仅仅添加这个会导致gradle bootRun失败,出现“org.apache.catalina.LifecycleException: A child container failed during start”的错误,即使没有传递任何-D参数。 - tkruse
通过挑选我想要的属性来解决问题,就像在https://dev59.com/EmAg5IYBdhLWcg3wWp7-的答案中一样。 - tkruse

8

1
是的,这个解决方案可行。但我不想将这段代码放在源代码控制下。我认为“最正确”的解决方案是直接在命令行中传递这些选项。有没有办法实现呢? - Evgeny
1
帖子中提到的链接有一种通过命令行传递它们的方式。 - suman j
你能说一下它与使用bootRun相比有什么不同吗?测试会使用这个吗?类似这样的问题。 - MozenRath

5

@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

确实已经通过了测试。

希望这能帮助其他尝试有条件运行测试的人。


3
bootRun {
  args = ['myProgramArgument1', 'myProgramArgument2']
}

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

你能展示一下如何在Application.class或Bootstrap.class中使用这些参数吗?(我正在使用Grails 3.x.x) - Stefano Scarpanti

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

在特定于bootRun的线程上提到这一点并不是没有意义的!我来到这里是因为这篇文章是关于在Gradle下编译/运行Spring Boot应用程序的jvm选项的磁铁。 (我找到的所有添加java.net.http.httpclient日志记录的建议都说“将其添加到bootRunjvmArgs”中。但什么也没发生。

因此,如果您从Docker容器中运行Gradle构建的Spring Boot应用程序,则需要像这样将JVM参数添加到项目的Dockerfile中的env变量中,例如-

...
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,以便容器在必要时也会重新构建应用程序。 - jdolan

2

看起来它能够正常工作:

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

1
我遇到了类似的问题,bootRun需要一些参数,但是我不想修改bootRun,因为我想保持一些灵活性并坚持标准的bootRun行为。我的建议是添加一些自定义任务(比如bootRunDev、bootRunProxy),这些任务扩展了bootRun,如下面的代码片段所描述的那样。
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提供的帮助。


0

为了作为Docker容器的开发,请将以下内容添加到run_script.sh文件中的JAVA_OPTS:

JAVA_OPTS="-XX:+UseG1GC -Xms512m -Xmx2048m --add-opens java.base/java.util=ALL-UNNAMED -Dspring.profiles.active=$PROFILE,discovery"


0
你可以按照以下方式传递参数:
gradlew bootRun -Pargs=-Dspring.profiles.active=DEV,--POSTGRES_DB_HOST=jdbc:postgresql://localhost:5432/postgres,--POSTGRES_USR=postgres,--POSTGRES_PWD=postgres

如果您使用 build.gradle.kts 文件:
tasks.bootRun {
    if (project.hasProperty("args")) {
        args(project.properties["args"]?.toString()?.split(","))
    }
}

如果你使用build.gradle:
bootRun {
    if (project.hasProperty('args')) {
        args project.args.split(',')
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接