-cp 에 디렉터리를 적으면 그 안의 클래스 파일만 찾는다. jar 를 넣으려면 와일드카드를 쓴다.
java -cp "/opt/app/lib/*" com.example.Main
java -cp "app.jar:/opt/app/lib/*" com.example.Main
와일드카드에 대해 알아 둘 것이 셋이다. * 는 JVM 이 해석하므로 셸이 확장하지 않도록 따옴표로 감싼다. 그 디렉터리의 .jar 와 .JAR 만 포함하며 하위 디렉터리는 훑지 않는다. 그리고 확장 순서는 정해져 있지 않으므로 같은 클래스가 여러 jar 에 있으면 어느 것이 이길지 보장되지 않는다.
하위 디렉터리까지 넣어야 하면 목록을 만들어 넘긴다.
CP=$(find /opt/app/lib -name '*.jar' | paste -sd:)
java -cp "app.jar:$CP" com.example.Main
구분자는 리눅스·macOS 가 :, Windows 가 ; 다.
클래스패스가 길어져 명령줄 길이 제한에 걸리면 Java 9 이상은 @ 인자 파일을 쓸 수 있다.
-cp /opt/app/app.jar:/opt/app/lib/a.jar:/opt/app/lib/b.jar
-Xmx2g
java @/opt/app/java.args com.example.Main
-cp 를 주면 환경 변수 CLASSPATH 는 무시된다. 둘을 함께 쓰려면 직접 이어 붙인다.
export CLASSPATH="/opt/app/lib/*"
java com.example.Main
환경 변수 방식은 어느 값이 적용됐는지 추적하기 어려워 운영에서는 권장하지 않는다. 실행 스크립트에 -cp 로 명시하는 편이 낫다.
java -jar app.jar
-jar 를 쓰면 -cp 가 완전히 무시된다. 이때 클래스패스는 jar 의 META-INF/MANIFEST.MF 에 적힌 Class-Path 만 유효하다.
Main-Class: com.example.Main
Class-Path: lib/a.jar lib/b.jar
Class-Path 의 경로는 jar 파일 위치 기준 상대경로이고, 공백으로 구분하며, 디렉터리 와일드카드를 쓸 수 없다. 외부 jar 를 더하려면 -jar 대신 -cp 와 메인 클래스를 직접 지정한다.
java -cp "app.jar:/opt/jdbc/*" com.example.Main
java -verbose:class -cp "app.jar:/opt/app/lib/*" com.example.Main | grep -i postgres
특정 클래스가 어느 jar 에서 왔는지 보려면 다음을 쓴다.
System.out.println(
Class.forName("org.postgresql.Driver").getProtectionDomain().getCodeSource().getLocation());
같은 클래스가 여러 jar 에 있어 생기는 문제를 찾을 때 유용하다. 버전이 다른 라이브러리가 겹치면 NoSuchMethodError 가 난다. ClassNotFoundException 과 달리 클래스는 찾았는데 시그니처가 다른 상황이므로, 클래스패스에 같은 라이브러리가 두 벌 있는지 먼저 본다.