日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java是如何加载资源文件的?(源码解毒)

發(fā)布時(shí)間:2025/4/14 java 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java是如何加载资源文件的?(源码解毒) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

? ? ? ? ?上文提到應(yīng)老板要求開(kāi)發(fā)一個(gè)測(cè)試工具能方便的加載存于文件中的測(cè)試參數(shù),當(dāng)時(shí)考慮既然是測(cè)試,把測(cè)試參數(shù)文件和測(cè)試類(lèi)放在一起豈不是很方便,但是老板說(shuō):我的需求是你把測(cè)試參數(shù)文件放到統(tǒng)一文件夾下比如resources目錄下,當(dāng)然你做的這個(gè)也可以保留。 好吧,既然老板都說(shuō)了,我就開(kāi)干唄,主要問(wèn)題是如何在CaseloaderSupplier中獲取resources文件夾的路徑,很多人的第一反應(yīng)是直接new File("/src/test/resources")不行嗎? 當(dāng)然是不行的,因?yàn)橥ㄟ^(guò)maven編譯以后會(huì)把資源文件拷貝到target目錄下邊,直接通過(guò)file是定位不到的。唯一的解決方案(我目前感覺(jué)是唯一的)是使用Java提供的抽象方法:resources。可以通過(guò)Class.getResources()或者ClassLoader.getResources()。 Class.getResource底層也是將加載任務(wù)委托給ClassLoader做的。 當(dāng)然,在做這個(gè)之前對(duì)resource不是太熟悉,只是偶爾會(huì)調(diào)用一下接口,所以感覺(jué)還是詳細(xì)了解一下resource心里有底一點(diǎn),google了很多文章,大概意思是getResource("")獲取的是當(dāng)前調(diào)用類(lèi)路徑,比如當(dāng)前類(lèi)路徑為file:/Users/caiyao/workservice/test-caseloader/target/classes/base/ (打包以后的),getResource("/")這個(gè)獲取的是classpath的根目錄,比如file:/Users/caiyao/workservice/test-caseloader/target/classes/(注意:沒(méi)有包名)。問(wèn)題是老板要求測(cè)試參數(shù)類(lèi)要在test包下的resources目錄里,這樣獲取的是main的包下面的,那么怎樣才能讓在測(cè)試的時(shí)候(執(zhí)行@Test方法)加載test包下的資源呢? 當(dāng)然在思考這個(gè)問(wèn)題之前,我還是在執(zhí)行@Test時(shí)試了一下,令人迷惑的是,在執(zhí)行@Test的時(shí)候拿到的已經(jīng)是test包下的資源了!!!file:/Users/caiyao/workservice/test-caseloader/target/test-classes/ 如何辦到的,詳細(xì)看下源碼:

首先看下getResource方法

public java.net.URL getResource(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResource(name);
}
return cl.getResource(name);
}
c1.getResource(name)這句可以看出Class是把獲取資源委托給ClassLoader來(lái)執(zhí)行的。進(jìn)入ClassLoader的getResoure方法(java.lang.ClassLoader#getResource): 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;
}
從這里可以看出Java獲取資源和加載類(lèi)是同樣的道理,使用的是雙親委托機(jī)制,首先執(zhí)行父類(lèi)加載器的getResource方法,如果父類(lèi)加載器為空則執(zhí)行Bootstrap的類(lèi)加載器,如果父類(lèi)加載的getResource沒(méi)有獲取到值
再?gòu)淖约旱纳舷挛牟檎屹Y源,該方法真正執(zhí)行操作的是findResource(name)這個(gè)步驟,進(jìn)入java.lang.ClassLoader#findResource,ClassLoader的默認(rèn)實(shí)現(xiàn)直接返回null,應(yīng)該看ClassLoader的實(shí)現(xiàn)類(lèi)URLClassLoader
(從很少的源碼閱讀經(jīng)驗(yàn)中我發(fā)現(xiàn)通過(guò)IDE斷點(diǎn)調(diào)試能避免很多不必要的代碼閱讀,讓注意力更集中于關(guān)注的這條線),從調(diào)試的過(guò)程可以看出,最后的結(jié)果是由AppClassLoader返回,這點(diǎn)很重要,后面要用到: public URL findResource(final String name) {
/*
* The same restriction to finding classes applies to resources
*/
URL url = AccessController.doPrivileged(
new PrivilegedAction<URL>() {
public URL run() {
return ucp.findResource(name, true);
}
}, acc);

return url != null ? ucp.checkURL(url) : null;
} AccessController.doPrivileged方法是一個(gè)native方法,無(wú)法通過(guò)IDE進(jìn)去調(diào)試,但是可以對(duì)ucp.findResource(name,true)打斷點(diǎn),通過(guò)調(diào)試可以看出正是該方法的執(zhí)行返回了
file:/Users/caiyao/workservice/test-caseloader/target/test-classes/,要注意一點(diǎn)這里調(diào)用的findResource是通過(guò)該類(lèi)的一個(gè)成員屬性u(píng)cp中進(jìn)去的,ucp持有該方法的一些上下文,斷點(diǎn)進(jìn)sun.misc.URLClassPath#findResource方法: public URL findResource(String var1, boolean var2) {
int[] var4 = this.getLookupCache(var1);

URLClassPath.Loader var3;
for(int var5 = 0; (var3 = this.getNextLoader(var4, var5)) != null; ++var5) {
URL var6 = var3.findResource(var1, var2);
if (var6 != null) {
return var6;
}
}

return null;
}
從該方法可以看出URL是通過(guò)this.getNextLoader(var4, var5))返回的Loader里得到的,而this正是上面URLClassLoader的成員屬性u(píng)cp,回到URLClassLoader類(lèi)中尋找ucp的初始化代碼,可以看到一個(gè)單參數(shù)的構(gòu)造方法: public URLClassLoader(URL[] urls) {
super();
// this is to make the stack depth consistent with 1.1
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkCreateClassLoader();
}
ucp = new URLClassPath(urls);
this.acc = AccessController.getContext();
}然后需要找到urls是重什么地方傳遞過(guò)來(lái)的,我以前大致了解過(guò)Java的類(lèi)加載過(guò)程,知道類(lèi)加載器是由AppClassLoader / ExtClassLoader / BootstrapClassLoader這樣的一個(gè)層級(jí)結(jié)構(gòu)組成,它們由Launcher初始化,從上面
已經(jīng)得知最后的資源路徑是由AppClassLoader得到,所以可以猜測(cè)AppClassLoader是URLClassLoader的子類(lèi),可能在Launcher中初始化,從Launcher中可以找到如下代碼: static class AppClassLoader extends URLClassLoader {
final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);

public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
final String var1 = System.getProperty("java.class.path");
final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
public Launcher.AppClassLoader run() {
URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
return new Launcher.AppClassLoader(var1x, var0);
}
});
}
證實(shí)了猜想,AppClassLoader從java.class.path變量中獲取資源路徑,而java.class.path這個(gè)變量由在什么地方設(shè)置的呢? 肯定在執(zhí)行java命令時(shí)設(shè)置的參數(shù),可以 ps aux |grep Test1(Test1是我測(cè)試類(lèi)的名字)查看到
當(dāng)前執(zhí)行的測(cè)試進(jìn)程的信息,果然在執(zhí)行Java命令時(shí)把如下兩個(gè)路徑都加到了classpath中:

/Users/caiyao/workservice/test-caseloader/target/test-classes
/Users/caiyao/workservice/test-caseloader/target/classes

而且test-classes在前面,從sun.misc.URLClassPath#findResource中的代碼可以看出,在遍歷classpath的時(shí)候,一旦發(fā)現(xiàn)了一個(gè)存在就不會(huì)再往后遍歷,所以在執(zhí)行test方法的時(shí)候只會(huì)拿到test目錄,至于為什么在執(zhí)行Test的時(shí)候自動(dòng)把test的資源路徑加到了classpath里,這個(gè)我沒(méi)有再深入研究,猜測(cè)應(yīng)該是maven做的操作,因?yàn)閠arget這個(gè)目錄就是maven的規(guī)定。

終于找到原因,可以安心的寫(xiě)代碼了~~~

轉(zhuǎn)載于:https://www.cnblogs.com/caiyao/p/9306719.html

總結(jié)

以上是生活随笔為你收集整理的Java是如何加载资源文件的?(源码解毒)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲网友自拍 | 天天干天天舔天天射 | 爱露出 | 欧美另类在线播放 | 亚洲二级片 | 公侵犯人妻一区二区三区 | 999毛片| 99久久久久久久久 | 超碰caoporen | 制服丝袜亚洲色图 | 国产理论片 | 在线国产区| 精品免费在线 | 国产精品人人爽人人爽 | 国产伦精品视频一区二区三区 | 久久靖品| a级黄色影院 | 国产精品中文久久久久久 | 污片免费在线观看 | 男人的天堂免费视频 | 动漫美女视频 | 亚洲女人天堂成人av在线 | 超碰97人人干 | 亚洲国产福利 | 日韩欧美三区 | 成人综合在线观看 | 黄色小视频在线免费看 | 欧美四虎 | 欧美成人三级精品 | 亚洲风情第一页 | 国产成人小视频在线观看 | 色综合一区二区 | 极品销魂美女一区二区三区 | 黄色一级在线观看 | 女人性做爰100部免费 | 羞羞答答一区 | 精品九九 | 波多野结衣视频免费在线观看 | 超碰最新在线 | 免费日韩av | 国产91精品看黄网站在线观看 | 久久亚洲av午夜福利精品一区 | 4438国产精品一区二区 | 成人免费看视频 | 国产精欧美一区二区三区白种人 | 黄91在线观看 | 91亚色| 国产免费无遮挡吸奶头视频 | 91av观看 | 成人性生交生交视频 | 台湾chinesehdxxxx少妇 | 亚洲大片精品 | 在线亚洲网站 | 手机版av | 日韩久久在线 | av片一区二区三区 | ,一级淫片a看免费 | 91av亚洲 | 丰满的女邻居 | 日日爱669| 亚洲欧洲久久 | 一级免费观看视频 | 黄色大片免费观看视频 | 午夜影院色 | 黄色大片网址 | 国产在线精品一区二区 | 国产手机在线播放 | 神马午夜我不卡 | 中文无码日韩欧 | 国产精品二区一区二区aⅴ 一卡二卡三卡在线观看 | 亚洲一区二区黄片 | 在线日本视频 | gv天堂gv无码男同在线观看 | 国产 日韩 欧美 制服丝袜 | 九一爱爱 | 一区二区三区视频观看 | 不卡av片| 黄色小说在线观看视频 | 51久久 | 女人的天堂网 | 乱老熟女一区二区三区 | 自拍偷拍亚洲天堂 | 可以免费观看的毛片 | 亚洲2022国产成人精品无码区 | 欧美9999| 国产九色91回来了 | 99综合色 | www,xxx日本| 性感少妇在线观看 | 国产日韩欧美精品在线 | 国产精品第72页 | 亚洲咪咪| 精品人妻无码一区二区三区蜜桃一 | 久久久亚洲精品视频 | 少妇又色又紧又大爽又刺激 | n0659极腔濑亚美莉在线播放播放 | 最新中文字幕在线观看视频 | 一本一道久久a久久 | 免费观看日韩 |