Web 容器中通過 ServletContext.getRealPath("/") 獲取項目根路徑是常識,但JAR 包類無法直接訪問 ServletContext。本文提供一種零依賴、線程安全、部署無關的通用方案:啟動階段注入 System Property。
ServletContextListener、Filter 或 Servlet.init())獲取真實路徑。System.setProperty("app.root.path", realPath)。System.getProperty("app.root.path") 讀取。import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class AppPathInitializer implements ServletContextListener {
private static final String PROP_KEY = "app.root.path";
@Override
public void contextInitialized(ServletContextEvent sce) {
String realPath = sce.getServletContext().getRealPath("/");
if (realPath != null) {
System.setProperty(PROP_KEY, realPath);
} else {
// 兜底:嘗試從類路徑推導
String fallback = AppPathInitializer.class.getProtectionDomain()
.getCodeSource().getLocation().getPath();
System.setProperty(PROP_KEY, fallback);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.clearProperty(PROP_KEY);
}
}
<listener>
<listener-class>com.yourpkg.AppPathInitializer</listener-class>
</listener>
public final class AppPathUtil {
private static final String PROP_KEY = "app.root.path";
public static String getAppRootPath() {
String path = System.getProperty(PROP_KEY);
if (path == null) {
throw new IllegalStateException("App root path not initialized! Ensure AppPathInitializer runs first.");
}
return path;
}
public static File getAppRootDir() {
return new File(getAppRootPath());
}
public static File resolve(String relativePath) {
return new File(getAppRootDir(), relativePath);
}
}
System.setProperty 即可)。System Property 進程級可見,多線程讀取無競態。@BeforeClass 設置屬性即可模擬真實環境。ApplicationListener<ContextRefreshedEvent> 或 @PostConstruct Bean 注入。getRealPath 返回反斜槓,建議工具類內統一 path.replace('\\', '/')。myapp.root.path),避免互覆蓋。SecurityManager 禁止 System.setProperty,需改用 JNDI 或環境變量傳遞。| 方案 | 優點 | 缺點 | 推薦指數 |
|---|---|---|---|
| System Property(本文) | 簡單、無依賴、可測試 | 需啟動階段注入 | ⭐⭐⭐⭐⭐ |
| ServletContext 存 Application Scope | 標準 Web 方式 | JAR 無法直接訪問,需傳遞引用 | ⭐⭐⭐ |
| JNDI 資源 | 容器管理、集群友好 | 配置複雜、過度設計 | ⭐⭐ |
類路徑推導 Class.getResource("") | 無額外配置 | JAR 內路徑、Fat JAR、類加載器差異導致極不穩定 | ⭐ |
總結:「啟動時注入 System Property,運行時靜態讀取」是 JAR 包獲取項目絕對路徑的最優解,簡單、穩健、可測試,推薦作為項目基礎設施標準化組件。