Dev Study
← 解説「JAR・WAR・マニフェスト・実行可能 JAR」に戻る

サンプルコードで身につける: JAR・WAR・マニフェスト・実行可能 JAR

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1用語早見表: JAR・WAR とその中のフォルダ名

このレッスンの用語の早見表です。、、 はどれも zip 形式の入れ物で、違いは中の決まったフォルダと、何に渡して動かすかです。WAR と EAR は、アプリをサーバ製品に渡すための形で、Node には近いものがありません。

用語早見表(JAR・WAR とその中のフォルダ名)表
用語 | 一言で
手元では: 何として見えるか
近いもの: Node / NestJS で近いもの
 
JAR(Java Archive)| .class や設定ファイルをまとめた zip
手元では: app.jar。jar tf で中を一覧できる
近いもの: npm パッケージ(当たらない点は5本目)
 
マニフェスト | JAR の中の説明書き
手元では: META-INF/MANIFEST.MF の Main-Class の行
近いもの: 無い
 
META-INF | JAR の中の説明用のフォルダ
手元では: jar tf の先頭に出る META-INF/
近いもの: 無い
 
WAR(Web ARchive)| Web アプリをサーバに渡すための形
手元では: demo.war。Tomcat の webapps/ に置く
近いもの: 無い
 
WEB-INF | WAR の中の、外から直接は見えない部分
手元では: WEB-INF/classes、WEB-INF/lib、
WEB-INF/web.xml
近いもの: 無い
 
実行可能 JAR | 依存の JAR も入れ、java -jar だけで動く JAR
手元では: Spring Boot が作る JAR
近いもの: dist/ と node_modules を一緒に運ぶこと
 
fat JAR / uber JAR | 実行可能 JAR がこう呼ばれることがある
手元では: Spring Boot のリファレンスにも出てくる語
近いもの: dist/ と node_modules を一緒に運ぶこと
 
EAR(Enterprise ARchive)| 複数の WAR や JAR をまとめる形
手元では: このコースでは名前だけ
近いもの: 無い

2JAR の中を一覧し、マニフェストを読む

2つのを コマンドで JAR にまとめ、中を一覧した記録です。 は名どおりのフォルダに入り、jar コマンドが を足しています。の の行が の入口です。この JAR は 1,800 バイトでした。

JDK 25(Temurin 25.0.4.1)。# の行は補足コマンド出力
$ jar --create --file app.jar --main-class com.example.app.Main -C out .
$ jar tf app.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/app/
com/example/app/Main.class
com/example/greet/
com/example/greet/Greeter.class
 
# 中の META-INF/MANIFEST.MF を取り出して表示したもの
Manifest-Version: 1.0
Created-By: 25.0.4.1 (Eclipse Adoptium)
Main-Class: com.example.app.Main
 
$ java -jar app.jar
Hello, world!

3WAR の中を一覧し、Tomcat に置く

HTTP に応答するクラス(。後のレッスンで扱います)を1つだけ入れた最小の WAR です。自分の .class は の下に入ります。この WAR は依存が無いので はありません。 の に置くと /demo/hello で応答し、 の中を直接取りに行くと 404 でした。

tomcat:11.0-jdk25-temurin(Tomcat 11.0.26)。... は省略した行コマンド出力
$ jar --list --file /work/out/demo.war
META-INF/
META-INF/MANIFEST.MF
WEB-INF/
WEB-INF/classes/
WEB-INF/classes/hello/
WEB-INF/classes/hello/HelloServlet.class
WEB-INF/web.xml
 
# demo.war を Tomcat の webapps/ に置いて起動した後
$ curl -si http://localhost:18080/demo/hello
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
...
hello from servlet
...
$ curl -si http://localhost:18080/demo/WEB-INF/web.xml | head -1
HTTP/1.1 404

4Spring Boot の実行可能 JAR の中

4.1.1 の最小の Web アプリをビルドしてできた JAR の中です。自分の .class は に、 は に 34 本入っています。マニフェストの Main-Class は Spring Boot の起動用のクラスで、自分の を持つクラスは に書かれています。仕組みは後のレッスンで扱います。

$ jar tf target/demo-0.0.1-SNAPSHOT.jar(BOOT-INF/lib の中身と起動用クラスを除いた抜粋)コマンド出力
META-INF/
META-INF/MANIFEST.MF
...
org/springframework/boot/loader/
BOOT-INF/
BOOT-INF/classes/
...
BOOT-INF/classes/com/example/demo/DemoApplication.class
BOOT-INF/classes/com/example/demo/HelloController.class
BOOT-INF/classes/application.properties
...
BOOT-INF/lib/
...
 
# BOOT-INF/lib/ の下の JAR は 34 本
# マニフェスト(META-INF/MANIFEST.MF)のうち2行
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: com.example.demo.DemoApplication

5たとえが当たらない点: 普通の JAR は依存を持たない

外部のライブラリ()を使うアプリを、jar コマンドで JAR にした記録です。JAR の中に依存は入らず、依存の一覧もありません。java -jar では、そのライブラリを使う行で失敗しました。なら中の package.json に依存が書いてありますが、JAR では依存の JAR の場所を自分でに書きます。 は、この手間を無くすための形です。

JDK 25(Temurin 25.0.4.1)。... は省略した行コマンド出力
$ jar tf app.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/app/
com/example/app/Main.class
com/example/greet/
com/example/greet/Greeter.class
 
$ java -jar app.jar
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtils
at com.example.greet.Greeter.greet(Greeter.java:7)
at com.example.app.Main.main(Main.java:7)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang3.StringUtils
...
 
$ java -cp app.jar:lib/commons-lang3-3.21.0.jar com.example.app.Main
Hello, World!

図やコードに出てくる用語(タップで説明)