1依存の無い2クラスを、3つのコマンドで
ソース2ファイルから始めて、、、 の順に打った記録です。 out は、に合わせて out/com/example/app/ のようなフォルダを自分で作って を置きます。jar はそれを app.jar にまとめ、 で指定した入口の名をに書きます。
$ find . -type f | sort./src/com/example/app/Main.java./src/com/example/greet/Greeter.java$ javac -d out $(find src -name "*.java")$ find out -type f | sortout/com/example/app/Main.classout/com/example/greet/Greeter.class$ java -cp out com.example.app.MainHello, world!$ jar --create --file app.jar --main-class com.example.app.Main -C out .$ ls -l app.jar && jar tf app.jar-rw-r--r-- 1 root root 1800 Oct 1 22:26 app.jarMETA-INF/META-INF/MANIFEST.MFcom/com/example/com/example/app/com/example/app/Main.classcom/example/greet/com/example/greet/Greeter.class$ java -jar app.jarHello, world!
2依存の JAR があると、コンパイルにも実行にも -cp が要る
Greeter が外部のライブラリ()を使うように変えた版です。 は自分でダウンロードして に置きました。置いただけではコンパイラは見てくれず、 で場所を教えると通ります。実行のときも同じで、教えないと (クラスが見つからない)で落ちます。[exit 1] は失敗の終了コードを記録した行です。
$ find . -type f | sort./lib/commons-lang3-3.21.0.jar./src/com/example/app/Main.java./src/com/example/greet/Greeter.java$ javac -d out $(find src -name "*.java")src/com/example/greet/Greeter.java:3: error: package org.apache.commons.lang3 does not existimport org.apache.commons.lang3.StringUtils;^src/com/example/greet/Greeter.java:7: error: cannot find symbolreturn "Hello, " + StringUtils.capitalize(name) + "!";^symbol: variable StringUtilslocation: class Greeter2 errors[exit 1]$ javac -d out -cp lib/commons-lang3-3.21.0.jar $(find src -name "*.java")$ java -cp out com.example.app.MainException in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtilsat 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.StringUtilsat java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)... 2 more[exit 1]$ java -cp out:lib/commons-lang3-3.21.0.jar com.example.app.MainHello, World!
3自分の JAR に依存は入らない
上の続きで、app.jar を作って起動したものです。 で見ると、中にあるのは自分の .class 2個だけで、commons-lang3 は入っていません。そのため app.jar は失敗します。動かすには、app.jar と を -cp に並べ、入口のクラスを名指しします。-jar を付けると -cp の指定は無視されるので、この2つは一緒に使えません。
$ jar --create --file app.jar --main-class com.example.app.Main -C out .$ jar tf app.jarMETA-INF/META-INF/MANIFEST.MFcom/com/example/com/example/app/com/example/app/Main.classcom/example/greet/com/example/greet/Greeter.class$ java -jar app.jarException in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/lang3/StringUtilsat 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.StringUtilsat java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)... 2 more[exit 1]$ java -cp app.jar:lib/commons-lang3-3.21.0.jar com.example.app.MainHello, World!$ java -cp "app.jar:lib/*" com.example.app.MainHello, World!
4Spring を Maven 無しで動かす: JAR を9本集める
7.0.9 の入口になる を使うために、手で集めた JAR の一覧と大きさです。自分が直接使うのは spring-context ですが、それが必要とする JAR、さらにその先が必要とする JAR を辿ると9本になりました。lib/* と書けばまとめて指定できますが、書き下すと最後のコマンドの長さになります。出力の beans defined: 5 は、 が管理している部品()の定義の数です。
$ ls -l lib/*.jar | awk "{print \$5, \$9}"73737 lib/commons-logging-1.3.5.jar3819 lib/jspecify-1.0.0.jar51745 lib/micrometer-commons-1.16.7.jar83914 lib/micrometer-observation-1.16.7.jar426204 lib/spring-aop-7.0.9.jar928155 lib/spring-beans-7.0.9.jar1399435 lib/spring-context-7.0.9.jar2035755 lib/spring-core-7.0.9.jar327140 lib/spring-expression-7.0.9.jar$ javac -d out -cp "lib/*" $(find src -name "*.java")$ java -cp "out:lib/*" com.example.app.MainHello, Spring without Maven!beans defined: 5##### the same, classpath spelled out$ java -cp out:lib/commons-logging-1.3.5.jar:lib/jspecify-1.0.0.jar:lib/micrometer-commons-1.16.7.jar:lib/micrometer-observation-1.16.7.jar:lib/spring-aop-7.0.9.jar:lib/spring-beans-7.0.9.jar:lib/spring-context-7.0.9.jar:lib/spring-core-7.0.9.jar:lib/spring-expression-7.0.9.jar com.example.app.MainHello, Spring without Maven!beans defined: 5
51本抜くとどこで気づけるか
9本から1本ずつ抜いて、コンパイルと実行を試した結果です(各1回)。コンパイラが型を調べるときに必要になる JAR はコンパイルで気づけますが、Spring の内部だけが使う JAR は、コンパイルが通って実行時に落ちます。下の3本は抜いてもこの実行では動きましたが、エラーが起きた経路や Web アプリでは必要になったので、不要とは言えません。
抜いた JAR javac java 最初のエラーspring-context エラー エラー package org.springframework.stereotype does not existspring-beans エラー エラー class file for org.springframework.beans.factory.support.DefaultListableBeanFactory not foundspring-core エラー エラー class file for org.springframework.core.io.DefaultResourceLoader not foundspring-aop 通る エラー NoClassDefFoundError: org/springframework/aop/TargetSourcespring-expression 通る エラー NoClassDefFoundError: org/springframework/expression/ParserContextcommons-logging 通る エラー NoClassDefFoundError: org/apache/commons/logging/LogFactoryjspecify 通る 動く -micrometer-observation 通る 動く -micrometer-commons 通る 動く -=== without commons-logging-1.3.5.jarjavac exit 0java exit 1 (classes compiled with full lib)Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactoryat org.springframework.context.support.AbstractApplicationContext.<init>(AbstractApplicationContext.java:187)at org.springframework.context.support.GenericApplicationContext.<init>(GenericApplicationContext.java:122)at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:68)at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:102)at com.example.app.Main.main(Main.java:7)Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory