What is JarLauncher and what exactly does it do at startup?
answer
- Main-Class runs first = JarLauncher, not your app
- std classloader can't read jar-in-jar → needs LaunchedClassLoader
- reads Start-Class, reflectively calls its main
- classpath.idx orders BOOT-INF/lib
- siblings: WarLauncher, PropertiesLauncher
basics
~20 sJarLauncher is Spring Boot's bootstrap class named as Main-Class in the manifest. The JVM runs it first; it builds a classloader that can read the nested jars in BOOT-INF/lib, then calls your app's Start-Class main method.
solid answer
~40 sJarLauncher (`org.springframework.boot.loader.launch.JarLauncher` in Boot 3.2+) is the manifest's Main-Class, so `java -jar` runs it first, not your app. The standard JVM classloader can't reach classes packaged inside a jar-within-a-jar, so JarLauncher's job is to set up a classloader — LaunchedClassLoader — that understands the nested BOOT-INF/lib jars and BOOT-INF/classes. It reads the entries (guided by classpath.idx for ordering), builds that classloader, then reflectively invokes the `main` method of the class named by the manifest's Start-Class. From that point your @SpringBootApplication runs with every dependency resolvable. WarLauncher and PropertiesLauncher are sibling launchers for other layouts. This indirection is exactly why a plain `java -cp` on the fat jar without the launcher would fail to find nested classes.
code
text · 15 linesMETA-INF/MANIFEST.MF
---------------------
Manifest-Version: 1.0
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: com.example.MyApp
Spring-Boot-Version: 3.4.0
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
# Flow at `java -jar app.jar`:
# JVM -> JarLauncher.main()
# -> build LaunchedClassLoader over BOOT-INF/classes + BOOT-INF/lib/*.jar
# -> read Start-Class = com.example.MyApp
# -> reflectively call MyApp.main(args)go deeper
Know JarLauncher is the entry point that starts your app.
Explain it builds a classloader for nested jars then calls Start-Class.main via reflection.
Discuss LaunchedClassLoader, classpath.idx ordering, and why -cp bypass fails.
Weigh nested-jar classloading vs exploded/layered for container startup and caching.
## Why a launcher is needed at all The standard Java application classloader can read classes and resources from a jar, and from jars listed on the classpath — but it **cannot read a jar that is nested inside another jar**. A Spring Boot fat jar deliberately stores dependencies as **whole nested jars** under `BOOT-INF/lib`. So something has to teach the runtime how to load classes out of those nested jars. That something is a **Launcher**. ## JarLauncher's identity In the manifest: ``` Main-Class: org.springframework.boot.loader.launch.JarLauncher Start-Class: com.example.MyApp ``` Because `Main-Class` is what `java -jar` executes, **the JVM runs JarLauncher first**, never your application directly. The loader classes (`org.springframework.boot.loader.*`) are stored **unpacked at the root of the outer jar** precisely so the ordinary system classloader can load JarLauncher itself before any nested-jar handling exists. ## What JarLauncher does, step by step 1. **Locate the archive** it was launched from. 2. **Enumerate the classpath**: `BOOT-INF/classes` plus every nested jar in `BOOT-INF/lib`. The **`classpath.idx`** file (added in later Boot versions) records the order so the classpath is deterministic and matches build order. 3. **Create a `LaunchedClassLoader`** (a `URLClassLoader` subclass) whose URLs point into the nested entries. In modern Boot this reads nested content directly; older versions registered a custom `jar:` URL protocol handler (`org.springframework.boot.loader.jar.Handler`) so that `jar:file:/app.jar!/BOOT-INF/lib/x.jar!/...` URLs resolved. 4. **Read `Start-Class`** from the manifest. 5. **Reflectively invoke** `Start-Class.main(String[])` on a thread whose context classloader is the LaunchedClassLoader. Your `SpringApplication.run(...)` now executes with all dependencies visible. ## Sibling launchers - **WarLauncher** — for executable wars (`WEB-INF/classes`, `WEB-INF/lib`, plus `WEB-INF/lib-provided`). - **PropertiesLauncher** — configurable via a `loader.path` property/env, lets you add external directories to the classpath; useful when you want to override or supplement jars without rebuilding. ## Common gotchas - **`java -cp app.jar com.example.MyApp` fails** — bypassing the launcher means the nested lib jars aren't on the classpath, so dependency classes are `NoClassDefFoundError`. You must go through `java -jar` (i.e., through JarLauncher) or explode the jar. - **Slightly slower cold start / different classloading** than a fully exploded classpath, because of the nested reading. For containers, many teams **explode the jar** (or use **layered jars**) and run with `java -cp` on the exploded directory using the JarLauncher-equivalent `org.springframework.boot.loader.launch.JarLauncher` main, or via the exploded layout — trading the single-file convenience for faster/cache-friendlier startup. - **You cannot nest a fat jar inside another fat jar** as a normal dependency — nested jars must be uncompressed-stored appropriately; the plugin handles this, but hand-assembled layouts can break. ## When it matters in interviews Understanding JarLauncher explains *why* `java -jar` is required, *why* dependencies aren't merged, and *how* Spring Boot achieves a single self-contained artifact without a servlet container.
- Why can't you launch the app with `java -cp app.jar com.example.MyApp`?The plain classloader from `-cp` cannot read jars nested inside BOOT-INF/lib, so dependency classes aren't found (NoClassDefFoundError). Only JarLauncher (via `java -jar`) sets up a classloader that reads the nested jars — or you must explode the jar first.
- What is PropertiesLauncher used for?It's an alternative launcher that lets you extend the classpath at runtime via a `loader.path` property/env variable, so you can add external directories or override jars without rebuilding the fat jar.
saying these in an interview costs you the question
- Saying the JVM directly runs your @SpringBootApplication main (it runs JarLauncher).
- Claiming the default JVM classloader can read nested jars out of the box.
- Confusing JarLauncher with the Spring ApplicationContext bootstrap — it's a pre-Spring classloading step.