119

I'm developing simple Spring web application that communicates with remote host and I would like to test it locally behind corporate proxy. I use "Spring Boot" gradle plugin and the question is how can I specify proxy settings for JVM?

I have try several ways to do it:

  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"

But it seems like none of them work - "NoRouteToHostException" throws in "network" code. Also, I have added some extra code to debug JVM start arguments:

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

And only one argument was printed: "-Dfile.encoding=UTF-8".

If I set system property in code:

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

Everything works just fine!

Evgeny
  • 1,413
  • 2
  • 12
  • 16

9 Answers9

131

Original Answer (using Gradle 1.12 and Spring Boot 1.0.x):

The bootRun task of the Spring Boot gradle plugin extends the gradle JavaExec task. See this.

That means that you can configure the plugin to use the proxy by adding:

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

to your build file.

Of course you could use the systemProperties instead of jvmArgs

If you want to conditionally add jvmArgs from the command line you can do the following:

bootRun {
    if ( project.hasProperty('jvmArgs') ) {
        jvmArgs project.jvmArgs.split('\\s+')
    }
}

gradle bootRun -PjvmArgs="-Dwhatever1=value1 -Dwhatever2=value2"

Updated Answer:

After trying out my solution above using Spring Boot 1.2.6.RELEASE and Gradle 2.7 I observed that it was not working as some of the comments mention. However, a few minor tweaks can be made to recover the working state.

The new code is:

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

for hard-coded arguments, and

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

    }
}

for arguments provided from the command line

geoand
  • 60,071
  • 24
  • 172
  • 190
  • 5
    I would like to not have this options "hardcoded" in build file. It would be great to have possibility to specify proxy settings. I.e. - using command-line arguments. – Evgeny Aug 01 '14 at 12:15
  • Does not work: "> Could not find property 'args' on root project". – Evgeny Aug 01 '14 at 12:26
  • Did you correctly copy the code? I have made an update. There is no `args` property. – geoand Aug 01 '14 at 12:28
  • 7
    I tried today and the only way this work, is to surrond the list of string by square brackets, like bootRun { jvmArgs = ["-Dhttp.proxyHost=xxxxxx", "-Dhttp.proxyPort=xxxxxx"] } – Valentino Dell'Aica Oct 08 '14 at 14:36
  • What version of gradle are you using? – geoand Oct 08 '14 at 15:07
  • I also had to put the square brackets in to avoid an error. I'm using Gradle 2.1. I would have guessed this to be a Groovy requirement rather than a Gradle requirement? –  Oct 15 '14 at 18:37
  • @WillieWheeler That sounds correct, but I would have to try it out. I have only used the code above on Gradle 1.9-1.12 – geoand Oct 15 '14 at 20:08
  • @AdamArold What version of Gradle are you using? – geoand Oct 09 '15 at 13:49
  • @AdamArold Check my updated answer that works for the latest versions of Spring Boot and Gradle – geoand Oct 09 '15 at 14:37
  • What I put over there is `jvmArgs = ["-Dloader.path=/Users/xyz/Documents/keys"]` – Jack Zhang Apr 12 '16 at 20:58
  • I am using spring boot 1.3.3 and gradle 2.10, it is not working for me. What I put over there is `jvmArgs = ["-Dloader.path=/Users/xyz/Documents/keys"]` – Jack Zhang Apr 12 '16 at 21:23
  • @JackZhang Are you sure the argument is not being passed in your code? You can also debug the gradle build, by inserting `println` statements in the `bootRun` task to see if your command line argument is actually being picked up – geoand Apr 13 '16 at 14:37
  • I tried to put the `println jvmArgs` in bootRun just now, it does not print anything, but I checked the log4j log, I do see `/Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/bin/java -Dloader.path=/Users/xyz/Documents/keys -cp /Users/wenjiezhang/Desktop/.....`, would it because I have both `-Dloader.path` and `-cp` (Although, I did not put `cp` by myself) here? – Jack Zhang Apr 14 '16 at 20:49
  • @JackZhang I don't know what the problem is from your description. Do you have a sample GitHub project to share? – geoand Apr 15 '16 at 06:49
  • @geoand, thanks for taking time to look into my issue, I have created a repo on github for sample purpose, https://github.com/wenjiezhang2013/stackoverflow-sample, in this example, if I have a `application.yml` file under `/Users/wenjiezhang/Desktop/xyz`, and run `gradle bootRun`, it will prints `null`, however, if I have this file under `main/resources`, it will be loaded correctly. And I do see `Command: /Library/Java/JavaVirtualMachines/jdk1.8.0_72.jdk/Contents/Home/bin/java -Dloader.path=/Users/wenjiezhang/Desktop/xyz` from log. – Jack Zhang Apr 17 '16 at 21:55
  • @JackZhang The problem is not in the Gradle script, but in the fact that `loader.path` is not something that is used by Spring Boot to alter the path where properties are read. Check out [this](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html) for all the details – geoand Apr 20 '16 at 10:38
  • Let me update my sample project later, it causes some confusion, I was just trying to use `loader.path` to include some external yaml file into the classpath in my work project, so I can read it from my code, it did not work. When I was creating the sample project, I thought there is no difference between a configuration file (application.yml) vs some other yaml file I want to include in the classpath, so I made it this way. Thanks for helping, by the time you saw my comment, you can go back to check github repo. BTW, you are a such nice person, thank you so much for trying to help me. – Jack Zhang Apr 20 '16 at 18:41
  • @JackZhang No worries! Just trying to help when I have the time :) – geoand Apr 21 '16 at 07:23
82
bootRun {
  // support passing -Dsystem.property=value to bootRun task
  systemProperties = System.properties
}

This should pass all JVM options to the app started via bootRun.

Marvin Frommhold
  • 1,040
  • 8
  • 7
  • 3
    This is by far the best way to pass command line options to JVM – anubhava Feb 17 '16 at 22:54
  • 1
    @Marvin Frommhold, thanks for your answer. The approach is incredibly straightforward. For noobs like me, it would be helpful if you added a bit more detail. Suggestions: (1) show the gradle command line call with the arguments; (2) show how to reference the arguments in Spring Boot, e.g., @Value("${property:default}"); (3) A screenshot of the IntelliJ dialog passing the params would also be helpful. – Brett Mar 02 '16 at 15:08
  • 1
    Sadly, for me, just adding this causes gradle bootRun to fail horribly with "org.apache.catalina.LifecycleException: A child container failed during start" even when not passing any -D params – tkruse Jul 13 '16 at 12:03
  • Solved by cherry-picking the properties I want as in an answer to http://stackoverflow.com/questions/23689054 – tkruse Jul 13 '16 at 12:34
8

In gradle build script, define systemProperties for run task.

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

and gradle run should accept this value.

Or define a project level property as mentioned in http://forums.gradle.org/gradle/topics/how_can_i_provide_command_line_args_to_application_started_with_gradle_run

suman j
  • 6,710
  • 11
  • 58
  • 109
  • 1
    Yes, this solution works. But I would like to not have this code under source control. I beleive that the "most right" solution is to pass this options directly in command line. Is it any way for it? – Evgeny Aug 01 '14 at 11:52
  • 1
    The link mentioned in the post has a way of passing them from command line – suman j Aug 01 '14 at 12:25
  • can you tell how it compares to using bootRun? what is different? do tests use this? something like that – MozenRath Jun 13 '21 at 21:03
5

@marvin, thanks for your post it was very helpful.

Sharing how I used it:

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

I have JUnit tests that I wanted to skip unless a property was used to include such tests. Using JUnit Assume for including the tests conditionally:

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

Doing this with gradle required that the system property provided at the time of running gradle build, shown here,

gradle build -Ddeep.test.run=true

was indeed passed through to the tests.

Hope this helps others trying out this approach for running tests conditionally.

Rishik Dhar
  • 51
  • 1
  • 4
3
bootRun {
  args = ['myProgramArgument1', 'myProgramArgument2']
}

Using jvmArgs may cause JVM start issues. Using args allows you to pass your custom program arguments

Cristian Botiza
  • 121
  • 1
  • 2
2

It seems to work:

bootRun {
    systemProperties "property1": "value1", "property2": "value2"
}
Regent
  • 5,142
  • 3
  • 21
  • 35
levsa
  • 930
  • 9
  • 16
1

I got into a similar problem, bootRun needed some parameters but I wouldn't feel like modifying bootRun as I want to keep some flexibility and stick to standard bootRun behaviour. My suggestion is to add some custom tasks (let's say bootRunDev, bootRunProxy) that extends bootRun, as described in the following code snippet

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'
    }
}

I don't have an environment to exercise the script but I used this approach to pass profile to spring using the property spring.profiles.active. Credits should go to Karol Kaliński

Evelino Bomitali
  • 173
  • 2
  • 13
1

It's worth mentioning, here, that some systems that use Gradle and Spring Boot are starting JVM outside of build.gradle, e.g. in a Dockerfile.

It's not pointless to mention this on a thread specifically about bootRun! I wound up here because this particular post is a magnet for searches about jvm options in the context of a Spring Boot app compiled / run under gradle. (All the advice I found for adding java.net.http.httpclient logging said "add it to bootRun's jvmArgs". Nothing happened, though.

So, if you happen to run your gradle-built Spring Boot app from a Docker container, you'll want to add your JVM params to an env var in your project's Dockerfile, like so, e.g.-

...
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
Kevin-Prichard
  • 147
  • 1
  • 7
  • I'm here for the same reason, so thank you for posting this. However, how do you combine this approach with the `gradle bootRun` task? I'd like to use bootRun so that the container will also rebuild the application as necessary. – jdolan Mar 29 '21 at 17:04
0

For development as Docker Container add to run_script.sh as JAVA_OPTS

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

Dave Kraczo
  • 748
  • 9
  • 9