Backend Development 10 min read

How Spring Boot’s Fat Jar Enables One‑Click Java Deployment

Spring Boot’s Fat Jar packages all application code, dependencies, and an embedded server into a single executable JAR, breaking the parent‑delegation model with a custom class loader and protocol handler, enabling simple ‘java -jar’ execution, streamlined deployment, and benefits for microservices and Docker layering.

Cognitive Technology Team
Cognitive Technology Team
Cognitive Technology Team
How Spring Boot’s Fat Jar Enables One‑Click Java Deployment

In Java development, traditional project deployment separates application code and dependencies, using the

-cp

option to specify the classpath. Spring Boot’s Fat Jar (a self‑contained executable JAR) allows developers to run the entire application with

java -jar app.jar

. This article analyzes the runtime principles of Spring Boot Fat Jar and how it achieves “out‑of‑the‑box” usability.

1. Core Design Concept of Fat Jar

1.1 What Is a Fat Jar?

A Fat Jar (full name “Fat JAR”) is a self‑contained Java archive whose key characteristics are:

Embedded all dependencies : project code, third‑party libraries (e.g., Spring framework, database drivers), and an embedded server (Tomcat, Jetty) are packaged into a single JAR.

Self‑contained execution : no external dependencies or extra configuration are required; the application runs directly with the

java -jar

command.

1.2 Structure of a Spring Boot Fat Jar

Spring Boot builds a Fat Jar via Maven or Gradle plugins. Its directory layout is:

<code>express-locker.jar
├── BOOT-INF/
│   ├── classes/      (compiled project classes)
│   └── lib/         (all dependency JARs, e.g., sms-service.jar, payment.jar)
├── META-INF/
│   └── MANIFEST.MF  (metadata specifying the entry point)
└── org/springframework/boot/loader/ (Spring Boot launcher and class loader)</code>

Key components:

BOOT-INF/classes : stores the project's compiled classes.

BOOT-INF/lib : stores all dependency JARs.

org.springframework.boot.loader : custom launcher and class loader that break the parent‑delegation model and load nested JARs.

2. Breaking the Parent‑Delegation Model: Solving Nested JAR Loading

2.1 Limitations of the Java Class‑Loading Mechanism

Java’s native class loaders (Bootstrap, Extension, Application) follow the parent‑delegation model, which prioritizes parent loaders. While this ensures core class safety, it cannot directly load nested JARs (JARs inside other JARs). For example,

BOOT-INF/lib/sms-service.jar

is a nested JAR that standard loaders cannot access.

2.2 Spring Boot’s Solution

2.2.1 Custom Class Loader: LaunchedURLClassLoader

Spring Boot defines a custom class loader

LaunchedURLClassLoader

with the following core logic:

<code>public class LaunchedURLClassLoader extends URLClassLoader {
    // Override loadClass to break parent delegation
    @Override
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            // 1. Check if already loaded
            Class<?> loadedClass = findLoadedClass(name);
            if (loadedClass != null) return loadedClass;
            // 2. Check hidden packages (e.g., java., javax.)
            if (isHidden(name)) {
                return super.loadClass(name, resolve);
            }
            // 3. Prefer classes from BOOT-INF/classes
            try {
                Class<?> localClass = findClass(name);
                if (localClass != null) return localClass;
            } catch (ClassNotFoundException ex) {}
            // 4. Try parent loader
            try {
                return Class.forName(name, false, getParent());
            } catch (ClassNotFoundException ex) {}
            // 5. Finally load from BOOT-INF/lib (nested JARs)
            return findClass(name);
        }
    }
}
</code>

Loading order:

Prefer BOOT-INF/classes (project code).

Attempt loading from the parent loader (e.g., JVM built‑in classes).

Finally load nested JARs from BOOT-INF/lib (dependencies).

2.2.2 Custom Protocol Handler: Supporting Nested JAR Resource Access

Spring Boot extends

JarURLConnection

to parse nested JAR URLs such as

jar:file:express-locker.jar!/BOOT-INF/lib/sms-service.jar!/templates/alert.txt

, enabling multi‑level resource loading.

<code>public class JarURLConnection extends java.net.JarURLConnection {
    public InputStream getInputStream() throws IOException {
        String nestedPath = getEntryName();
        if (nestedPath.contains("!/")) {
            String[] parts = nestedPath.split("!/", 2);
            JarFile outerJar = new JarFile(parts[0]);
            JarEntry nestedEntry = outerJar.getJarEntry(parts[1]);
            return new NestedJarInputStream(outerJar, nestedEntry);
        }
        return super.getInputStream();
    }
}
</code>

3. Startup Process: From java -jar to Application Run

3.1 Key Role of MANIFEST.MF

The

MANIFEST.MF

file is the entry configuration for a Spring Boot Fat Jar. Important attributes include:

<code>Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.example.Application
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/</code>

Main-Class : specifies the JVM entry class (

JarLauncher

).

Start-Class : specifies the Spring Boot application’s main class (

Application

), which

JarLauncher

invokes via reflection.

3.2 Startup Flow Analysis

JVM launch : executing

java -jar express-locker.jar

loads

JarLauncher

and its

main

method.

Load dependencies :

JarLauncher

uses

LaunchedURLClassLoader

to load all JARs under

BOOT-INF/lib

.

Start embedded server : if the project is a web application, Spring Boot automatically starts the embedded Tomcat/Jetty server (default port 8080).

Execute main class : via reflection, the

Start-Class

’s

main

method is invoked, launching the Spring Boot application.

4. Real‑World Scenarios and Advantages

4.1 Rapid Deployment for Microservices and Standalone Apps

One‑click run : no complex classpath or dependency management; simply execute

java -jar

.

Version isolation : nested JARs avoid conflicts with system‑wide dependencies.

4.2 Convenience of Embedded Servers

Traditional Java web apps require deployment to an external server (e.g., Tomcat). Spring Boot Fat Jar bundles an embedded server, allowing developers to deliver a complete web service with only code changes.

4.3 Layered Docker Image Optimization

Since Spring Boot 2.3, the

Spring-Boot-Layers-Index

feature supports building layered Docker images, improving build speed and runtime performance.

5. Summary

Spring Boot Fat Jar’s ability to run directly stems from its unique nested JAR structure and custom class‑loading mechanism. By breaking the parent‑delegation model, providing a custom protocol handler, and configuring

MANIFEST.MF

, Spring Boot achieves self‑contained dependency loading and automatic embedded‑server startup, simplifying deployment and offering an efficient solution for microservices and standalone applications.

JavamicroservicesSpring BootClass LoaderFat Jar
Cognitive Technology Team
Written by

Cognitive Technology Team

Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.