在不同場景(單元測試、Web 容器、打包 JAR、命令列執行)下,獲取 classpath 的方式行為不同。記錄 4 種主流方法及輸出差異。
public class ClassPathDemo {
public static void main(String[] args) {
System.out.println("++++++++++++++++++++++++");
String path1 = System.getProperty("java.class.path");
String path2 = ClassPathDemo.class.getProtectionDomain()
.getCodeSource().getLocation().getPath();
String path3 = ClassPathDemo.class.getProtectionDomain()
.getCodeSource().getLocation().getFile();
String path4 = Thread.currentThread().getContextClassLoader()
.getResource("").getPath();
System.out.println("path 1 (java.class.path) = " + path1);
System.out.println("path 2 (CodeSource.getPath) = " + path2);
System.out.println("path 3 (CodeSource.getFile) = " + path3);
System.out.println("path 4 (ContextClassLoader) = " + path4);
System.out.println("++++++++++++++++++++++++");
}
}
| 方法 | 含義 | 典型輸出 (IDE 運行) | 適用場景 |
|---|---|---|---|
System.getProperty("java.class.path") | JVM 啟動時的 -cp 參數值 | D:\project\target\classes;D:\maven\repo\... | 檢視完整編譯時/運行時類路徑,含所有依賴 JAR |
Class.getProtectionDomain().getCodeSource().getLocation().getPath() | 該類別所在的 JAR/目錄路徑(URL 路徑) | /D:/project/target/classes/ | 定位特定類別的物理位置,判斷是否來自 JAR 或目錄 |
...getLocation().getFile() | 同上,但返回 URL 的 file 部分(含查詢參數) | /D:/project/target/classes/ | 少用,getPath() 通常足夠 |
Thread.currentThread().getContextClassLoader().getResource("").getPath() | 當前執行緒上下文類加載器的根資源路徑 | /D:/project/target/classes/ | Web 容器、OSGi、多類加載器環境獲取「當前可見」資源根目錄 |
%20),需 URLDecoder.decode(path, "UTF-8")。getResource("") 返回以 / 結尾的目錄 URL;getResource(".") 可能返回 null。path2/3 指向 JAR 檔本身(file:/app/app.jar!/BOOT-INF/classes/),path4 同樣。需用 ClassPathResource 或 ResourceLoader 讀取資源。path1 包含 target/test-classes 與 target/classes。ClassLoader.getResourceAsStream("path") 或 Spring ResourceLoader,勿手動拼路徑。ClassGraph、Reflections 或 Spring ClassPathScanningCandidateComponentProvider。path1 與 path4 對比。