How can I configure the heap size when starting a Spring Boot application with embedded Tomcat? - spring-boot

I am trying to deploy a Spring Boot powered web app to production. The app is built with Spring Boot 1.0.1 and has the default Tomcat 7 embedded as application server. I want to allocate larger memory to the app when start the app with java -jar myapp.jar command line.
Should I use JVM parameter such as -Xms -Xmx or use environment variable such as JAVA_OPTS? I have tried to look for the answer in documentation or google it, but I did not get an answer. Can anyone give some hints?

If starting the application with the spring-boot plugin:
mvn spring-boot:run -Drun.jvmArguments="-Xmx512m" -Drun.profiles=dev
Otherwise if running java -jar:
java -Xmx512m -Dspring.profiles.active=dev -jar app.jar

Since this is specifically a Spring Boot question, I'd argue that a more useful answer than #DaveSyer's is this:
You can drop a .conf file in the same directory as your WAR file that is effectively a shell script.
For example,
$ ls
myapp.conf
myapp.war
$ cat myapp.conf
export JAVA_OPTS="-Xmx1024m -Xms256m"
Any configuration you do there will be run before the Spring Boot embedded Tomcat starts up. Personally, I version control a .conf.example file in my application itself and then drop a copy of it on each server I deploy to.
Of course, anything you set in that .conf file is overridable with command-line operations.

Just use whatever normal mechanism you would to set up the JVM. Documentation is available on the command line:
$ java -X
...
-Xms<size> Set initial Java heap size
-Xmx<size> Set maximum Java heap size
...

For Spring Boot 2, you have to specify the heap size in the pom.xml file as below:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>-Xmx64m</jvmArguments>
</configuration>
</plugin>

For Spring Boot 1, the Maven argument to specify in the plugin configuration is jvmArguments, and the user property is run.jvmArguments:
mvn spring-boot:run -Drun.jvmArguments="-Xms2048m -Xmx4096m"
For Spring Boot 2, the Maven argument to specify in the plugin configuration is also jvmArguments, but the user property is now spring-boot.run.jvmArguments:
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Xms2048m -Xmx4096m"
So if you use the plugin configuration way, both for Spring Boot 1 and 2 you can do that:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>
-Xms4048m
-Xmx8096m
</jvmArguments>
</configuration>
</plugin>

Related

Remote debug or local debug with tomcat embedded in Spring boot

I am working on a new project which embedded a tomcat with the dependency spring-boot-starter-tomcat:2.5.3 (into vaadin-spring-boot-starter).
I am building my project into a .jar, and launching it with "mvn spring-boot:run".
But because of the embedded tomcat, I am unable to use the debug mode with Eclipse.
I have already try to launch a remote debug session, with :
MAVEN_OPTS= -Xmx1024M -XX:MaxPermSize=256M -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
Eclipse connects itself well, but breakpoints are not working and it shows me only one thread, without any more informations.
So, do you have any idea how can I make it works ?
Thanks you for your time !
When running application using mvn spring-boot:run you can attach debugger like this:
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:8000"
By providing spring-boot.run.jvmArguments system property.
Alternatively, you can build application first and then run it using the following command:
java -jar app.jar -Dagentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000
When you provide debugger configuration using MAVEN_OPTS, the debugger is attached to the Maven process, however, the application is running in a separate Java process without a debugger attached.
The easiest way to debug a Spring Boot application from an IDE is to not use Maven at all but instead directly launch the main method from the #SpringBootApplication class.
As a third solution, I have installed Spring Tools 4 on the Eclipse Marketplace.
It makes me able to launch a #SpringBootApplication in debug mode, like Leif Astrand said, but with an IHM (Boot Dashboard).
Another solution is described here:
https://vaadin.com/forum/thread/17519592/debug-with-intellij
This solution also helped me get around the problem of connecting the remote debugger, but breakpoints not being reached (see my comment above).
You can add a JVM arg to the config params of the plugin, like this:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- my edits start -->
<configuration>
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
</jvmArguments>
</configuration>
<!-- my edits end -->
</plugin>

Running Spring Boot "context loads" test in maven causes OutOfMemoryError

I have a multi-module Maven project with two modules being Spring Boot applications. Each of them has a simple test that the Spring application context loads successfully (my tests are very similar to this one). I run this tests with the following command in project root:
mvn -P IntegrationTests clean test
During context initialization things go out of my control, the application "eats" memory (heap size grows quickly to 4 gigabytes) and then the context fails to start with java.lang.OutOfMemoryError: PermGen space error (yes, I run it in Java 7).
Monitoring task manager during testing I noticed that maven spawns two new processes that have something to do with surefire plugin. I have no idea where it comes from, because I don't add the surefire plugin in my pom.xml.
Previously when encountered the same error somewhere I specified VM options (-Xmx256m -Xms128m -XX:MaxPermSize=256m -XX:PermSize=128m for example) and the problem was solved.
This time I tried to
set MAVEN_OPTS environment variable
set VM options (when running mvn test in IntelliJ IDEA) - it affected main java process but not its children
add -Drun.jvmArguments="..." in command line
but the problem persists.
Please help me to fight the OutOfMemoryError in tests.
Add Surefire plugin explicitly to module-specific pom.xml and configure VM options there. I like this solution because this way VM options are
passed to the spawned surefire processes (which should solve your problem)
affect only test application builds
shared between developers in your team
configurable independently for every module
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Xmx256m -Xms128m -XX:MaxPermSize=256m -XX:PermSize=128m</argLine>
</configuration>
</plugin>
<!-- your other plugins go here -->
</plugins>
</build>

How to include external configuration resources to classpath in Spring (Spring Boot)?

I have 3rd party library that is configured by placing properties file on the root of the classpath. That library is using getClass().getResourceAsStream("/file.properties") to load that file. As it is 3rd party, it is unmodifiable. I have placed that configuration file into external resources directory (not to be mistaken with resources from eg. Maven's or Gradle's directory structure.
Directory structure is like this.
How to run/configure Spring boot to include content of resources directory to the classpath so getResourceAsStream wil work?
On SE application I would simply do java -jar myApp.jar with classpath in MANIFEST and that would work.
EDIT:
Just a word of clarification - putting configuration file inside project resources (along sources) is missing the whole point. I want to keep configuration externalized.
Here is how you can do it:
1.- Change your spring-boot-maven-plugin configuration to enable the Spring Boot PropertiesLauncher:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
</configuration>
</plugin>
</plugins>
</build>
2.- Launch your Spring Boot Application setting the location of the external properties file:
java -jar -Dloader.path=PATH_TO_PROPERTIES_FOLDER spring-ms-0.0.1-SNAPSHOT.jar
Assuming this folders:
/home/user/
|--- file.properties
|--- spring-mg-0.0.1-SNAPSHOT.jar
You should launch it like this: java -jar -Dloader.path=/home/user spring-ms-0.0.1-SNAPSHOT.jar

Spring Boot - Could not resolve placeholder when ran from jar file

I'm running into this strange issue where I can run my Spring Boot application without problems from within Intellij, but when I do:
mvn clean package -Pst -Dspring.profiles.active=st && java -jar target/myapp-0.0.1-SNAPSHOT.jar
I can see errors saying Spring Boot cannot resolve the #Value placeholders.
ERROR o.s.boot.SpringApplication - Application startup failed
java.lang.IllegalArgumentException: Could not resolve placeholder
What I did to investigate was to get the jar file and extract the files like using jar xf myapp.jar and I can see the properties files in the classpath root. Initially I had this problem that Maven was not packaging my properties and statics from the main/resource folder, but I already resolved that with:
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>static</directory>
<targetPath>static</targetPath>
</resource>
Any comments, ideas what could I be missing here?
I managed to resolve this. It was really weird, it seems that I need to tell java in which profile to run the jar in e.g --spring.profiles.active=st.
mvn clean package -Pst -Dspring.profiles.active=st && java -jar target/myapp-0.0.1-SNAPSHOT.jar --spring.profiles.active=st
It is not Maven deciding, what Spring Profile you use, but the Spring container during every single execution of the jar. The differen profiles are all available. The Spring profile is used to adapt the executable to different environments by configuration.
There are additionally Maven profiles, but they configure the build of the executable, not the execution.

"mvn spring-boot:run": "/health" endpoint with project version

I'd like to use Spring Boot's actuator endpoint /info to show project metadata such as the Maven-provided project version.
To do so, I followed the appropriate part in Spring Boot's documentation.
The shown solution works for me when my Spring Boot application starts up with java -jar [...].
Just as the documentation says, it doesn't work when the application starts up with mvn spring-boot:run — in that case, my /info endpoint reports "version":"#project.version#".
The documentation mentions that one has to properly configure Spring Boot's Maven plugin, but I could not find any information about doing so.
How can I configure my Maven project in order to have a mvn spring-boot:run-started Spring Boot application to show project metadata?
Configure the spring-boot-maven-plugin with <addResources>false</addResources>.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.0.BUILD-SNAPSHOT</version>
<configuration>
<addResources>false</addResources>
</configuration>
</plugin>
Source

Resources