How Spring Boot’s Executable JAR Works: Inside the Maven Plugin and Loader

This article explains how the spring-boot-maven-plugin creates an executable JAR, details the internal JAR structure, the role of the JarLauncher and Spring Boot Loader classes, and shows how the custom class loader loads classes at runtime.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
How Spring Boot’s Executable JAR Works: Inside the Maven Plugin and Loader

Spring Boot provides the spring-boot-maven-plugin to package an application as an executable JAR. Adding the plugin to the pom.xml is enough:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

The generated executable-jar-1.0-SNAPSHOT.jar has the following internal layout:

├── META-INF
│   ├── MANIFEST.MF
│   └── maven
│       └── spring.study
│           └── executable-jar
│               ├── pom.properties
│               └── pom.xml
├── lib
│   ├── aopalliance-1.0.jar
│   ├── classmate-1.1.0.jar
│   ├── spring-boot-1.3.5.RELEASE.jar
│   ├── spring-boot-autoconfigure-1.3.5.RELEASE.jar
│   └── ...
├── org
│   └── springframework
│       └── boot
│           └── loader
│               ├── ExecutableArchiveLauncher$1.class
│               └── ...
└── spring
    └── study
        └── executablejar
            └── ExecutableJarApplication.class

Running the JAR with java -jar executable-jar-1.0-SNAPSHOT.jar starts the application because the MANIFEST.MF declares Main-Class: org.springframework.boot.loader.JarLauncher:

Manifest-Version: 1.0
Implementation-Title: executable-jar
Implementation-Version: 1.0-SNAPSHOT
Archiver-Version: Plexus Archiver
Built-By: Format
Start-Class: spring.study.executablejar.ExecutableJarApplication
Implementation-Vendor-Id: spring.study
Spring-Boot-Version: 1.3.5.RELEASE
Created-By: Apache Maven 3.2.3
Build-Jdk: 1.8.0_20
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.JarLauncher

The JarLauncher is a Spring Boot Loader utility that launches the class specified by Start-Class. Spring Boot Loader defines several abstract concepts:

Launcher : base class for different launchers (JarLauncher, WarLauncher, PropertiesLauncher).

Archive : abstraction of an archive file; JarFileArchive represents a JAR, ExplodedArchive a directory.

JarFile : wraps a JAR file and provides access to its entries.

Dependencies inside the JAR are referenced with URLs that contain the custom !/ separator, e.g.:

jar:file:/Users/Format/Develop/gitrepository/springboot-analysis/springboot-executable-jar/target/executable-jar-1.0-SNAPSHOT.jar!/lib/spring-boot-starter-web-1.3.5.RELEASE.jar!/

These URLs are handled by org.springframework.boot.loader.jar.Handler, a custom URL protocol.

JarLauncher Execution Process

The main method of JarLauncher simply creates an instance and calls launch(args):

public static void main(String[] args) {
    new JarLauncher().launch(args);
}
launch

registers the custom URL handler, builds a classpath from the lib directory, creates a LaunchedURLClassLoader, obtains the Start-Class from the manifest, and finally invokes the overloaded launch(args, mainClass, classLoader) method, which creates a MainMethodRunner and runs it in a new thread.

protected void launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception {
    Runnable runner = createMainMethodRunner(mainClass, args, classLoader);
    Thread runnerThread = new Thread(runner);
    runnerThread.setContextClassLoader(classLoader);
    runnerThread.setName(Thread.currentThread().getName());
    runnerThread.start();
}

The MainMethodRunner loads the start class, finds its main method, and invokes it.

@Override
public void run() {
    try {
        Class<?> mainClass = Thread.currentThread().getContextClassLoader()
            .loadClass(this.mainClassName);
        Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
        if (mainMethod == null) {
            throw new IllegalStateException(this.mainClassName + " does not have a main method");
        }
        mainMethod.invoke(null, new Object[]{ this.args });
    } catch (Exception ex) {
        UncaughtExceptionHandler handler = Thread.currentThread().getUncaughtExceptionHandler();
        if (handler != null) {
            handler.uncaughtException(Thread.currentThread(), ex);
        }
        throw new RuntimeException(ex);
    }
}

Custom Class Loader – LaunchedURLClassLoader

LaunchedURLClassLoader

overrides loadClass and defines its own loading rules:

If a root class loader exists, delegate to it.

Attempt to find the class locally using findClass (which searches the URLs built from the JAR and its dependencies).

Fall back to the standard parent‑class‑loader delegation.

The core of findClass resolves the class name to a path, obtains the resource via the URL class path, and defines the class:

protected Class<?> findClass(final String name) throws ClassNotFoundException {
    try {
        return AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
            public Class<?> run() throws ClassNotFoundException {
                String path = name.replace('.', '/').concat(".class");
                Resource res = ucp.getResource(path, false);
                if (res != null) {
                    return defineClass(name, res);
                } else {
                    throw new ClassNotFoundException(name);
                }
            }
        });
    } catch (PrivilegedActionException pae) {
        throw (ClassNotFoundException) pae.getException();
    }
}

A small test registers the custom URL handler, creates a LaunchedURLClassLoader with two dependency URLs, and loads classes such as org.springframework.boot.loader.JarLauncher and org.springframework.boot.SpringApplication.

// Register the handler
JarFile.registerUrlProtocolHandler();
LaunchedURLClassLoader classLoader = new LaunchedURLClassLoader(
    new URL[]{
        new URL("jar:file:/.../executable-jar-1.0-SNAPSHOT.jar!/lib/spring-boot-loader-1.3.5.RELEASE.jar!/"),
        new URL("jar:file:/.../executable-jar-1.0-SNAPSHOT.jar!/lib/spring-boot-1.3.5.RELEASE.jar!/")
    },
    LaunchedURLClassLoaderTest.class.getClassLoader()
);
classLoader.loadClass("org.springframework.boot.loader.JarLauncher");
classLoader.loadClass("org.springframework.boot.SpringApplication");
classLoader.loadClass("org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration");

Purpose of Spring Boot Loader

Spring Boot defines its own rules for executable JARs: third‑party dependencies are placed under /lib, URLs use the custom !/ syntax handled by org.springframework.boot.loader.jar.Handler, and the main class is JarLauncher (or WarLauncher for WAR files). These launchers start a new thread that runs the user’s SpringApplication. All of this is assembled by the spring-boot-maven-plugin.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

spring-bootexecutable JARMaven Pluginjar-launcher
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

0 followers
Reader feedback

How this landed with the community

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.