Build & Run the Jar
During development you start the app from your IDE or with ./mvnw spring-boot:run. On a server there is no IDE and usually no source code: you copy one file and run it. Spring Boot's executable jar contains your classes, every library and the embedded Tomcat, so the only thing the server needs is a Java runtime.
In this lesson you will build the jar, look inside it, run it with configuration options, use the tools jar mode that prepares it for containers, and run it as a Linux service that shuts down gracefully.
Building the jar
./mvnw clean package[INFO] Building jar: C:\...\academy\target\academy-0.0.1-SNAPSHOT.jar [INFO] Replacing main artifact C:\...\academy\target\academy-0.0.1-SNAPSHOT.jar with repackaged archive, adding nested dependencies in BOOT-INF/. [INFO] BUILD SUCCESS
(Paths shortened.) clean deletes the old target folder; package compiles, runs all tests, builds a normal jar, and then the Spring Boot Maven plugin repackages it into an executable one. If a test fails, no jar is built, which is exactly what you want. -DskipTests skips the tests; use it rarely, never as a habit to hide failures. With Gradle, ./gradlew build puts the jar in build/libs.
The academy jar is about 55 MB, because it carries everything it needs.
Inside the jar
A jar is a zip file. jar tf lists its contents (the academy jar has 256 entries); the important ones are:
META-INF/MANIFEST.MF says which class starts the jar
org/springframework/boot/loader/launch/JarLauncher.class Spring Boot's launcher
BOOT-INF/classes/application.properties your resources
BOOT-INF/classes/data.sql
BOOT-INF/classes/in/cricket/academy/... your compiled classes
BOOT-INF/lib/spring-boot-4.1.2.jar every dependency, as nested jars
BOOT-INF/lib/h2-2.4.240.jar
BOOT-INF/classpath.idx order of the nested jars
BOOT-INF/layers.idx layer information for containersJava cannot normally load jars nested inside a jar. Spring Boot's JarLauncher can: the manifest names it as the Main-Class, it sets up a class loader for BOOT-INF/lib, and then calls your AcademyApplication.main. This is why the jar runs with plain java -jar.
Running it
java -jar target/academy-0.0.1-SNAPSHOT.jar
java -jar target/academy-0.0.1-SNAPSHOT.jar --server.port=9000 --spring.profiles.active=prod
java -Xmx512m -jar target/academy-0.0.1-SNAPSHOT.jar- Arguments after the jar name with
--are Spring properties, with the highest priority, as you saw in Configuration. - Options before
-jargo to the JVM:-Xmx512mlimits the heap to 512 MB. - Environment variables (
SPRING_PROFILES_ACTIVE=prod,SPRING_DATASOURCE_PASSWORD=...) work too, and are the usual way on servers. - An
application.propertiesfile in the folder you start from overrides the one inside the jar, which is handy for server-specific settings.
Remember the "two Javas" problem from Prerequisites & Setup: the server's java -version must be 17 or later, matching what you compiled for.
The tools jar mode
Spring Boot jars contain a small built-in tool. Run it with -Djarmode=tools:
java -Djarmode=tools -jar target/academy-0.0.1-SNAPSHOT.jar help
java -Djarmode=tools -jar target/academy-0.0.1-SNAPSHOT.jar list-layersUsage: java -Djarmode=tools -jar application.jar Available commands: extract Extract the contents from the jar list-layers List layers from the jar that can be extracted help Help about any command dependencies spring-boot-loader snapshot-dependencies application
The four layers are groups of files that change at different speeds: third-party libraries rarely change, your own code changes on every build. extract unpacks the jar into a faster-starting layout, with one folder per layer:
java -Djarmode=tools -jar application.jar extract --layers --destination extractedextracted/application/application.jar extracted/dependencies/lib/ (84 library jars) extracted/snapshot-dependencies/ extracted/spring-boot-loader/
(This listing was made with find after the command, which itself prints nothing.) The next lesson uses exactly these folders in a Dockerfile, so that a code change rebuilds only the small application layer of the image.
Running as a Linux service
On a plain Linux server (a VPS), let systemd start the app at boot and restart it if it crashes. Create /etc/systemd/system/academy.service:
[Unit]
Description=Pune Cricket Academy API
After=network.target
[Service]
User=academy
WorkingDirectory=/opt/academy
EnvironmentFile=/opt/academy/academy.env
ExecStart=/usr/bin/java -Xmx512m -jar /opt/academy/academy.jar
SuccessExitStatus=143
Restart=on-failure
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now academy
sudo journalctl -u academy -fThe app runs as an unprivileged academy user, secrets come from an environment file readable only by that user, and journalctl shows the console log. Exit status 143 is what Java returns when stopped by SIGTERM, so systemd treats a normal stop as success. Put a reverse proxy such as Nginx in front to handle HTTPS, as shown in the Docker course. The Linux tutorial covers systemd and users in more depth.
Graceful shutdown and other runtime settings
- Graceful shutdown is on by default (
server.shutdown=graceful): onSIGTERM, Tomcat stops accepting new requests and lets running ones finish, for up to 30 seconds (spring.lifecycle.timeout-per-shutdown-phase). Deployments then do not cut off users mid-request. - Virtual threads: on Java 21 or later,
spring.threads.virtual.enabled=truemakes Tomcat handle each request on a lightweight virtual thread, which helps APIs that spend most of their time waiting for databases or other services.
Common mistakes
- Running the plain jar. With Gradle,
build/libsalso contains...-plain.jar, which is not executable; run the other one. - Old Java on the server.
UnsupportedClassVersionErrormeans the server's Java is older than the version you compiled for. - Secrets on the command line. Arguments are visible to other users in the process list; use an environment file with tight permissions.
- Skipping tests to "save time" and deploying a broken build. Let
packagerun them.
Key points
./mvnw clean packageruns tests and builds an executable jar intarget/; Gradle uses./gradlew buildandbuild/libs.- The jar contains your classes in
BOOT-INF/classes, libraries inBOOT-INF/lib, and Spring Boot'sJarLauncher. - Run it with
java -jar;--key=valuearguments and environment variables configure it. java -Djarmode=tools -jar app.jar extract --layerssplits it intodependencies,spring-boot-loader,snapshot-dependenciesandapplicationlayers for containers.- Use systemd (or containers) to run it as a service; graceful shutdown is the default.
Exercise
You must deploy academy.jar on an Ubuntu server with 2 GB of RAM. The database password must not appear in any file inside the jar or on the command line, the app must use the prod profile and port 8081, and it must restart automatically after a crash. Write the environment file and the ExecStart line, and list the commands to start the service and watch its log.
Show solution
# /opt/academy/academy.env (owner academy, permissions 600)
SPRING_PROFILES_ACTIVE=prod
SERVER_PORT=8081
SPRING_DATASOURCE_PASSWORD=<the real password>ExecStart=/usr/bin/java -Xmx768m -jar /opt/academy/academy.jar
Restart=on-failure
EnvironmentFile=/opt/academy/academy.envsudo chmod 600 /opt/academy/academy.env
sudo systemctl daemon-reload
sudo systemctl enable --now academy
sudo journalctl -u academy -fSpring Boot maps SPRING_PROFILES_ACTIVE, SERVER_PORT and SPRING_DATASOURCE_PASSWORD to the matching properties through relaxed binding. -Xmx768m leaves memory for the operating system and the database driver's buffers on a 2 GB machine.
Quick Quiz
1. What does ./mvnw package do if a test fails?
Tests run before packaging; a failure stops the build.
2. Where are your compiled classes inside a Spring Boot jar?
Libraries are in BOOT-INF/lib, and Spring Boot's launcher sits at the root.
3. In java -Xmx512m -jar app.jar --server.port=9000, which part is a Spring property?
Options before -jar go to the JVM; --key=value after the jar name are Spring properties.
4. What does graceful shutdown do?
It is on by default in Spring Boot, with a 30-second limit per phase.
Learn Spring Boot with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
