1target にできる2つの JAR
のあとの には が2つあります。 のほうは自分のだけを入れた普通の JAR(13エントリ・3,269バイト)で、それを包み直して依存とローダを足したものが 19,905,070 バイトのです。
$ cd target && ls -l *.jar *.jar.original-rw-r--r-- 1 root root 19905070 Oct 1 13:27 demo-0.0.1-SNAPSHOT.jar-rw-r--r-- 1 root root 3269 Oct 1 13:27 demo-0.0.1-SNAPSHOT.jar.original$ unzip -l demo-0.0.1-SNAPSHOT.jar.originalArchive: demo-0.0.1-SNAPSHOT.jar.originalLength Date Time Name--------- ---------- ----- ----0 2026-10-01 13:27 META-INF/167 2026-10-01 13:27 META-INF/MANIFEST.MF0 2026-10-01 13:27 com/0 2026-10-01 13:27 com/example/0 2026-10-01 13:27 com/example/demo/0 2026-10-01 13:27 META-INF/maven/0 2026-10-01 13:27 META-INF/maven/com.example/0 2026-10-01 13:27 META-INF/maven/com.example/demo/29 2026-10-01 13:27 application.properties771 2026-10-01 13:27 com/example/demo/HelloController.class733 2026-10-01 13:27 com/example/demo/DemoApplication.class1479 2026-10-01 13:18 META-INF/maven/com.example/demo/pom.xml59 2026-10-01 13:27 META-INF/maven/com.example/demo/pom.properties--------- -------3238 13 files
2MANIFEST.MF の Main-Class は自分のクラスではない
成果物の JAR に入っている の全文です。 は のローダである で、自分のクラスは という別の項目に書かれています。リファレンスは Launcher を「It is the actual Main-Class in your jar file, and it is used to setup an appropriate and ultimately call your () method.」と説明しています。
Manifest-Version: 1.0Created-By: Maven JAR Plugin 3.5.1Java-Version: 25Build-Jdk-Spec: 25Implementation-Title: demoImplementation-Version: 0.0.1-SNAPSHOTMain-Class: org.springframework.boot.loader.launch.JarLauncherStart-Class: com.example.demo.DemoApplicationSpring-Boot-Version: 4.1.1Spring-Boot-Classes: BOOT-INF/classes/Spring-Boot-Lib: BOOT-INF/lib/Spring-Boot-Classpath-Index: BOOT-INF/classpath.idxSpring-Boot-Layers-Index: BOOT-INF/layers.idx
3依存 JAR は無圧縮のまま並んでいる
で大きい順に5つ見た結果です。2列目の Stored は無圧縮という意味で、入れ子の JAR 34本はすべてこの形でした。全体の圧縮率は 1% で、成果物の大半は「すでに圧縮済みの JAR をそのまま並べたもの」です(webmvc だけの場合の値で、依存を足せば増えます)。
3623633 Stored 3623633 0% 2026-07-03 07:01 4bd7d8d3 BOOT-INF/lib/tomcat-embed-core-11.0.24.jar2226342 Stored 2226342 0% 1980-02-01 00:00 a59abb60 BOOT-INF/lib/spring-web-7.0.9.jar2035755 Stored 2035755 0% 1980-02-01 00:00 17e57eb1 BOOT-INF/lib/spring-core-7.0.9.jar1944003 Stored 1944003 0% 2026-07-08 01:30 86738493 BOOT-INF/lib/jackson-databind-3.1.5.jar1399435 Stored 1399435 0% 1980-02-01 00:00 096d6dc8 BOOT-INF/lib/spring-context-7.0.9.jar...20101026 19871250 1% 170 files
4素の Java で見る: 入れ子の JAR は1つのエントリでしかない
JAR は ZIP なので、java.util.zip だけで同じ形を作れます。外側から見ると、入れ子の JAR は PK で始まるバイト列を持つ1エントリで、中のクラスにたどり着くにはそのバイト列をもう一度 ZIP として開く係が要ります。 のローダが引き受けているのはこの役目です(このコードはローダの実装ではなく、構造を見るためのものです)。
5NestJS・Rust と並べる: 何を成果物に入れたか
同じ応答を返す3つのアプリで、ビルドの成果物と、実行に別途要るものを並べた実測値です。Spring Boot は依存を JAR の中に入れ、NestJS は成果物の外(node_modules)に置き、Rust は実行ファイルに結合しています。ただし Rust も libc・libm・libgcc_s には動的にリンクしています。
Spring Boot NestJS Rust(axum)ビルドの成果物 demo-0.0.1-SNAPSHOT.jar dist/ の9ファイル target/release/demo1個・19,905,070 B (.js 3・.d.ts 3・.map 3) 1個・1,979,160 B計 3,916 B依存の置き場 JAR の中 成果物の外 ソースからコンパイルして結合BOOT-INF/lib に34本 node_modules(本番依存のみで (Compiling 51行・自分を含む)98パッケージ・22,772 KB)実行に別途要るもの JRE(194,344 KB) Node 本体(122,893,672 B) libc など OS の共有ライブラリと node_modules起動コマンド java -jar demo.jar node dist/main.js ./demo