Java類加載器getResource行為簡單分析

?今天嘗試集成一個第三方SDK,在IDE里運行正常,放到服務器上卻遇到了NPE,反編譯一看,原來在這一行:

String path = Test.class.getClassLoader().getResource("").getPath();
// Test.class.getClassLoader().getResource("") == null

檢查一番,原來是classpath中只有jar包,沒有目錄。?Test.class.getClassLoader().getResource("")?返回classpath中第一個目錄的路徑。如果沒有目錄,返回null。

寫程序驗證,果然如此。

代碼1??驗證程序

import java.net.URL;public class A {public static void main(String... args) {checkResource("");checkResource("/resources/a.txt");checkResource("resources/a.txt");}public static void checkResource(String name) {System.out.println("resource:" + name);URL url = A.class.getClassLoader().getResource(name);System.out.println(url);if (url != null) {System.out.println(url.getPath());}System.out.println("---------------------");}
}
$ javac A.java; jar cvf A.jar A.class resources/ ; java -cp A.jar A
# 程序輸出
resource:
null
---------------------
resource:/resources/a.txt
null
---------------------
resource:resources/a.txt
jar:file:/root/A.jar!/resources/a.txt
file:/root/A.jar!/resources/a.txt
---------------------

查看JDK11源代碼:

代碼2??ClassLoader

public URL getResource(String name) {URL url;if (parent != null) {url = parent.getResource(name);} else {url = getBootstrapResource(name);}if (url == null) {url = findResource(name);}return url;
}

ClassLoader是一個抽象類,實際使用的是URLClassLoader。在JDK11里,URLClassLoader將操作委托給URLClassPath。URLClassPath內部使用3個加載器:Loader、FileLoader和JarLoader,分別從遠程(HTTP)、本地目錄和jar包中加載資源。

JarLoader使用JarFile讀取jar文件。JarFile派生自ZipFile,加載jar文件項的代碼是

JNIEXPORT jlong JNICALL
Java_java_util_zip_ZipFile_getEntry(JNIEnv *env, jclass cls, jlong zfile,jbyteArray name, jboolean addSlash)
{
#define MAXNAME 1024jzfile *zip = jlong_to_ptr(zfile);jsize ulen = (*env)->GetArrayLength(env, name);char buf[MAXNAME+2], *path;jzentry *ze;if (ulen > MAXNAME) {path = malloc(ulen + 2);if (path == 0) {JNU_ThrowOutOfMemoryError(env, 0);return 0;}} else {path = buf;}(*env)->GetByteArrayRegion(env, name, 0, ulen, (jbyte *)path);path[ulen] = '\0';if (addSlash == JNI_FALSE) {ze = ZIP_GetEntry(zip, path, 0);} else {ze = ZIP_GetEntry(zip, path, (jint)ulen);}if (path != buf) {free(path);}return ptr_to_jlong(ze);
}

注意到?path[ulen] =?'\0'?這一行,當?name ==?""?時,JarLoader無法加載資源。

FileLoader使用?file =?new?File(dir, name.replace('/', File.separatorChar))?加載資源,當?name ==?""?時,?new?File("")?返回當前目錄。因此當classpath中只有jar包時,?Test.class.getClassLoader().getResource("") ==?null?,而如果classpath包含目錄,Test.class.getClassLoader().getResource("") ==?null?返回第一個目錄路徑。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/87537.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/87537.shtml
英文地址,請注明出處:http://en.pswp.cn/web/87537.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【CodeTop】每日練習 2025.7.4

Leetcode 1143. 最長公共子序列 動態規劃解決,比較當前位置目標和實際字符串的字母,再根據不同情況計算接下來的情形。 class Solution {public int longestCommonSubsequence(String text1, String text2) {char[] t1 text1.toCharArray();char[] t2…

ES6從入門到精通:Promise與異步

Promise 基礎概念Promise 是 JavaScript 中處理異步操作的一種對象,代表一個異步操作的最終完成或失敗及其結果值。它有三種狀態:Pending(進行中)、Fulfilled(已成功)、Rejected(已失敗&#xf…

數據結構:二維數組(2D Arrays)

目錄 什么是二維數組? 二維數組的聲明方式 方式 1:靜態二維數組 方式 2:數組指針數組(數組中存放的是指針) 方式 3:雙指針 二級堆分配 💡 補充建議 如何用“第一性原理”去推導出 C 中…

HAProxy 和 Nginx的區別

HAProxy 和 Nginx 都是優秀的負載均衡工具,但它們在設計目標、適用場景和功能特性上有顯著區別。以下是兩者的詳細對比:1. 核心定位特性HAProxyNginx主要角色專業的負載均衡器/代理Web 服務器 反向代理/負載均衡設計初衷高性能流量分發高并發 HTTP 服務…

基于Java+SpringBoot的健身房管理系統

源碼編號:S586源碼名稱:基于SpringBoot的健身房管理系統用戶類型:多角色,用戶、教練、管理員數據庫表數量:13 張表主要技術:Java、Vue、ElementUl 、SpringBoot、Maven運行環境:Windows/Mac、JD…

【MySQL安裝-yum/手動安裝,卸載,問題排查處理完整文檔(linux)】

一.使用Yum倉庫自動安裝 步驟1:添加MySQL Yum倉庫 sudo rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el7-6.noarch.rpm步驟2:安裝MySQL服務器 sudo yum install mysql-server -y步驟3:啟動并設置開機自啟 sudo systemctl start mysqld sudo systemct…

自定義線程池-實現任務0丟失的處理策略

設計一個線程池,要求如下:隊列最大容量為10(內存隊列)。當隊列滿了之后,拒絕策略將新的任務寫入數據庫。從隊列中取任務時,若該隊列為空,能夠從數據庫中加載之前被拒絕的任務模擬數據庫 (TaskDa…

【NLP入門系列四】評論文本分類入門案例

🍨 本文為🔗365天深度學習訓練營 中的學習記錄博客🍖 原作者:K同學啊 博主簡介:努力學習的22級本科生一枚 🌟?;探索AI算法,C,go語言的世界;在迷茫中尋找光芒…

Ubuntu安裝ClickHouse

注:本文章的ubuntu的版本為:ubuntu-20.04.6-live-server-amd64。 Ubuntu(在線版) 更新軟件源 sudo apt-get update 安裝apt-transport-https 允許apt工具通過https協議下載軟件包。 sudo apt-get install apt-transport-htt…

C++26 下一代C++標準

C++26 將是繼 C++23 之后的下一個 C++ 標準。這個新標準對 C++ 進行了重大改進,很可能像 C++98、C++11 或 C++20 那樣具有劃時代的意義。 一:C++標準回顧 C++ 已經有 40 多年的歷史了。過去這些年里發生了什么?這里給出一個簡化版的答案,直到即將到來的 C++26。 1. C++9…

【MySQL】十六,MySQL窗口函數

在 MySQL 8.0 及以后版本中,窗口函數(Window Functions)為數據分析和處理提供了強大的工具。窗口函數允許在查詢結果集上執行計算,而不必使用子查詢或連接,這使得某些類型的計算更加高效和簡潔。 語法結構 function_…

微型氣象儀在城市環境的應用

微型氣象儀憑借其體積小、成本低、部署靈活、數據實時性強等特點,在城市環境中得到廣泛應用,能夠為城市規劃、環境管理、公共安全、居民生活等領域提供精細化氣象數據支持。一、核心應用場景1. 城市微氣候監測與優化熱島效應研究場景:在城市不…

【仿muduo庫實現并發服務器】eventloop模塊

仿muduo庫實現并發服務器一.eventloop模塊1.成員變量std::thread::id _thread_id;//線程IDPoller _poll;int _event_fd;std::vector<Function<Function>> _task;TimerWheel _timer_wheel2.EventLoop構造3.針對eventfd的操作4.針對poller的操作5.針對threadID的操作…

Redis 加鎖、解鎖

Redis 加鎖和解鎖的應用 上代碼 應用調用示例 RedisLockEntity lockEntityYlb RedisLockEntity.builder().lockKey(TradeConstants.HP_APP_AMOUNT_LOCK_PREFIX appUser.getAccount()).value(orderId).build();boolean isLockedYlb false;try {if (redisLock.tryLock(lockE…

在 Windows 上為 WSL 增加 root 賬號密碼并通過 Shell 工具連接

1. 為 WSL 設置 root 用戶密碼 在 Windows 上使用 WSL&#xff08;Windows Subsystem for Linux&#xff09;時&#xff0c;默認情況下并沒有啟用 root 賬號的密碼。為了通過 SSH 或其他工具以 root 身份連接到 WSL&#xff0c;我們需要為 root 用戶設置密碼。 設置 root 密碼步…

2730、找到最長的半重復子字符穿

題目&#xff1a; 解答&#xff1a; 窗口為[left&#xff0c;right]&#xff0c;ans為窗口長度&#xff0c;same為子串長度&#xff0c;窗口滿足題設條件&#xff0c;即只含一個連續重復字符&#xff0c;則更新ans&#xff0c;否則從左邊開始一直彈出&#xff0c;直到滿足條件…

MCP Java SDK源碼分析

MCP Java SDK源碼分析 一、引言 在當今人工智能飛速發展的時代&#xff0c;大型語言模型&#xff08;LLMs&#xff09;如GPT - 4、Claude等展現出了強大的語言理解和生成能力。然而&#xff0c;這些模型面臨著一個核心限制&#xff0c;即無法直接訪問外部世界的數據和工具。M…

[Linux]內核如何對信號進行捕捉

要理解Linux中內核如何對信號進行捕捉&#xff0c;我們需要很多前置知識的理解&#xff1a; 內核態和用戶態的區別CPU指令集權限內核態和用戶態之間的切換 由于文章的側重點不同&#xff0c;上面這些知識我會在這篇文章盡量詳細提及&#xff0c;更詳細內容還得請大家查看這篇…

設計模式-觀察者模式、命令模式

觀察者模式Observer&#xff08;觀察者&#xff09;—對象行為型模式定義&#xff1a;定義了一種一對多的依賴關系,讓多個觀察者對象同時監聽某一主題對象,在它的狀態發生變化時,會通知所有的觀察者.先將 Observer A B C 注冊到 Observable &#xff0c;那么當 Observable 狀態…

【Unity筆記01】基于單例模式的簡單UI框架

單例模式的UIManagerusing System.Collections; using System.Collections.Generic; using UnityEngine;public class UIManager {private static UIManager _instance;public Dictionary<string, string> pathDict;public Dictionary<string, GameObject> prefab…