問題情景
java應用程序在IDE運行正常,打成jar包后執行卻發生異常:
java.io.FileNotFoundException: class path resource [cert/sync_signer_pri_test.key] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/home/apps/application.jar!/BOOT-INF/classes!/cert/sync_signer_pri_test.key
at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:217)
at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:162)
at com.cfgdc.school.utils.JwtUtils.loadSyncSignerPrivateKey(JwtUtils.java:161)
上述錯誤信息指出文件路徑是class path resource [cert/sync_signer_pri_test.key],但無法解析為絕對路徑,因為它不在文件系統中,而是在一個jar包內。
原因分析
當應用程序打包成jar文件后,資源文件通常會被包含在jar內部。這時候,使用傳統的File來訪問資源文件可能會失敗,因為jar中的資源并不是文件系統中的一個實際文件,而是一個可以通過類加載器讀取的條目。
解決方案
要解決應用程序在JAR包中運行時無法讀取類路徑下文件的問題,需調整文件讀取方式,使用流(InputStream)代替直接文件訪問。
使用這種方式,既可以在IDE直接運行,也可以打成jar包運行。
以下是具體步驟:
步驟一:修改文件讀取方式
在JwtUtils
類的loadSyncSignerPrivateKey
方法中,將使用Resource.getFile()
的代碼替換為通過InputStream
讀取:
import org.springframework.core.io.ClassPathResource;
import org.apache.commons.io.IOUtils;// 修改前的代碼(導致異常)
// File file = new ClassPathResource("cert/sync_signer_pri_test.key").getFile();// 修改后的代碼
try (InputStream inputStream = new ClassPathResource("cert/sync_signer_pri_test.key").getInputStream()) {String privateKeyContent = IOUtils.toString(inputStream, StandardCharsets.UTF_8);// 處理privateKeyContent,例如加載私鑰
} catch (IOException e) {// 異常處理
}
步驟二:確保依賴項正確
如果使用Apache Commons IO的IOUtils
,需在pom.xml
中添加依賴:
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version>
</dependency>
步驟三:重新打包并測試
重新構建應用并打包為JAR,運行測試以確認問題已解決。
替代方案:外部化配置文件
若希望將證書文件放在JAR外部:
- 將文件移至外部目錄,如
/home/config/cert/sync_signer_pri_test.key
。 - 修改配置讀取路徑,使用絕對路徑或通過環境變量指定路徑:
String externalConfigPath = System.getenv("CONFIG_PATH") + "/cert/sync_signer_pri_test.key";
File file = new File(externalConfigPath);
- 確保部署時正確設置環境變量或路徑,并授予讀取權限。
總結
優先采用流方式讀取類路徑資源,確保JAR內資源正確訪問。若需外部配置,調整文件位置并修改讀取路徑。修改后重新部署應用即可解決問題。