Java加載資源文件時(shí)的路徑問題的解決辦法
加載資源文件比較常用的有兩種:
一、用ClassLoader,說到這里就不得不提一下ClassLoader的分類,java內(nèi)置的ClassLoader主要有三種,
第一種是根類加載器(bootstrap class loader),用C++來編寫,負(fù)責(zé)將一些關(guān)鍵的Java類,如java.lang.Object和其他一些運(yùn)行時(shí)代碼先加載進(jìn)內(nèi)存中。 所負(fù)責(zé)加載的包:BootStrp------>JRE/lib/rt.jar
第二種是擴(kuò)展類加載器(ExtClassLoader),由java類編寫,負(fù)責(zé)將JRE中的一些類加載進(jìn)內(nèi)存中。所負(fù)責(zé)加載的包: ExtClassLoader---------->JRE/lib/ext/*.jar
第三種是應(yīng)用類加載器(AppClassLoader)或者叫做系統(tǒng)類加載器,負(fù)責(zé)將CLASSPATH中的類加載到內(nèi)存中。可以通過ClassLoader.getSystemClassLoader()來獲取應(yīng)用類加載器;
再來所說加類載器的繼承,類加載器不是垂直繼承的父子關(guān)系,而是一種組合關(guān)系,可以通過實(shí)例化類加載器時(shí),將父類加載器的實(shí)例作為構(gòu)造參數(shù)傳到類加載器中。
關(guān)于類加載器的詳細(xì)資料,可以自行搜索。
獲取到應(yīng)用類加載器之后,就是獲取資源文件了,調(diào)用loader.getResource(path)可以加載相應(yīng)路徑下的資源文件,不能以‘/'開頭,關(guān)于包內(nèi)的資源可以把包當(dāng)做普通的文件夾,以'/'分隔每個(gè)包。
如:URL url2 = ClassLoader.getSystemClassLoader().getResource("demo/names.ser");是獲取demo包內(nèi)的names.ser序列化文件。
二、用需要加載的當(dāng)前類的getResource方法來加載,其實(shí)這個(gè)方法也是調(diào)用的加載這個(gè)類的類加載器來獲得資源文件的,只不過是獲取的參數(shù)不同。
(1)要想獲取class所在包內(nèi)的文件可以用相對(duì)路徑直接訪問包內(nèi)的資源;如:Demo1.class.getResource("names.ser");獲取的是Demo1的class文件所在包內(nèi)的資源
(2)要想獲取包外的資源文件必須以‘/'開頭,如URL url = Demo1.class.getResource("/demo/names.ser");獲取的是demo包內(nèi)的names.ser文件
其實(shí)第二種方式是對(duì)第一種方式的一個(gè)封裝,都是用的ClassLoader來加載的資源文件。為什么這么說呢?看一下Class類的源碼就知道:
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);
}
private String resolveName(String name) {
if (name == null) {
return name;
}
if (!name.startsWith("/")) {
Class c = this;
while (c.isArray()) {
c = c.getComponentType();
}
String baseName = c.getName();
int index = baseName.lastIndexOf('.');
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/')
+"/"+name;
}
} else {
name = name.substring(1);
}
return name;
}
getResource根據(jù)傳進(jìn)來的name值(即相對(duì)路徑或者絕對(duì)路徑的形式),我們看到經(jīng)過resolveName處理之后就調(diào)用了ClassLoader c1進(jìn)行了加載,ClassLoader的加載路徑的形式是不以‘/'開頭的相對(duì)路徑,那肯定是resolveName把路徑轉(zhuǎn)換了一把,再看看resolveName方法,首先判斷是不是以‘/'開頭,如果以‘/'開頭,則為相對(duì)路徑,否則就是絕對(duì)路徑,注意else這個(gè)代碼塊,它將第一個(gè)字符去除掉了,確實(shí)去除掉之后就符合了ClassLoader的加載路徑,而if塊中就根據(jù)把當(dāng)前類的包路徑截取,然后將.替換成了'/',并添加上那段相對(duì)路徑,也形成了符合ClassLoader的加載路徑。
相關(guān)文章
Java8如何使用Lambda表達(dá)式簡(jiǎn)化代碼詳解
這篇文章主要給大家介紹了關(guān)于Java8如何使用Lambda表達(dá)式簡(jiǎn)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11springcloud引入spring-cloud-starter-openfeign失敗的解決
這篇文章主要介紹了springcloud?引入spring-cloud-starter-openfeign失敗的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Springboot入門案例及部署項(xiàng)目的詳細(xì)過程
Spring Boot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開發(fā)過程,本文給大家分享一個(gè)入門案例使用Springboot1.5.9搭建,具體配置部署過程跟隨小編一起看看吧2021-07-07mybatis框架之mybatis中dao層開發(fā)的兩種方法
這篇文章主要介紹了mybatis框架之mybatis中dao層開發(fā)的兩種方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07關(guān)于ThreadLocal對(duì)request和response的用法說明
這篇文章主要介紹了關(guān)于ThreadLocal對(duì)request和response的用法說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08Springboot與Maven多環(huán)境配置的解決方案
多環(huán)境配置的解決方案有很多,我看到不少項(xiàng)目的多環(huán)境配置都是使用Maven來實(shí)現(xiàn)的,本文就實(shí)現(xiàn)Springboot與Maven多環(huán)境配置,感興趣的可以了解下2021-06-06