Java Gradle項(xiàng)目中的資源正確獲取方式
引言
一個(gè)Java Gradle項(xiàng)目會(huì)涉及到資源的訪問. 一般情況下會(huì)將當(dāng)前項(xiàng)目所需的資源文件全部放置于resources文件夾下, 無論是main文件下的source code 還是test文件夾下的test code.
都或多或少的涉及到獲取resources文件夾下的資源. 本文主要目的就是詳細(xì)的總結(jié)一下如何獲取resources文件夾下的資源.
兩個(gè)getResource方法
來看一個(gè)簡單的Java Gradle項(xiàng)目(稱呼其為simpleresource)的項(xiàng)目結(jié)構(gòu)
首先這個(gè)project執(zhí)行build之后會(huì)在根目錄下創(chuàng)建一個(gè)out目錄, 這個(gè)目錄存放所有的編譯結(jié)果(class文件以及資源文件). 如上圖所示production文件夾對(duì)應(yīng)的是source code而test文件夾對(duì)應(yīng)的是test code.
所有的資源都會(huì)存儲(chǔ)在resources文件夾內(nèi)部. 當(dāng)程序運(yùn)行時(shí)獲取的資源就是這個(gè)resources文件夾下的資源.
我們使用最多的獲取資源的方法有兩個(gè) Class.getResource 和 ClassLoader.getResource 但是這兩個(gè)方法傳遞參數(shù)與結(jié)果不同, 下面詳細(xì)分析一下這兩個(gè)方法參數(shù)以及返回值.
先看 ClassLoader 中的 getResource 方法. 只需要獲取類加載器對(duì)象即可(獲取方式不再贅述). 先看這個(gè)方法的API文檔相關(guān)的描述:
Finds the resource with the given name. A resource is some data (images, audio, text, etc) that can be accessed by class code in a way that is independent of the location of the code. The name of a resource is a ’/’-separated path name that identifies the resource.
This method will first search the parent class loader for the resource; if the parent is null the path of the class loader built-in to the virtual machine is searched. That failing, this method will invoke findResource(String) to find the resource.
從這個(gè)描述中可以得知提供資源的路徑(我理解的是相對(duì)路徑), 正常情況下該方法會(huì)返回資源完整的URL. 傳遞的參數(shù)有一個(gè)重要的注意事項(xiàng), 就是傳遞的參數(shù)不能夠以/ 開始, 這也是我為什么稱呼這個(gè)參數(shù)為資源的相路徑. 舉個(gè)例子
URL test = this.getClass().getClassLoader().getResource('/');
運(yùn)行上述代碼返回的結(jié)果是:
參考simpleresource的項(xiàng)目結(jié)構(gòu), 正確獲取 com.mainres 下的文件的正確做法是:
String name = 'com/mainres/testmain.txt';
URL test = this.getClass().getClassLoader().getResource(name);
結(jié)果為:
如果在表示資源路徑的字符串中加上 / 那么獲取到的URL依然為null
String name = '/com/mainres/testmain.txt';
URL test = this.getClass().getClassLoader().getResource(name);
宗上所述, 使用類加載器獲取資源的方式傳遞的參數(shù)為資源相對(duì)路徑(相對(duì)于resources文件夾的路徑), 既然是相對(duì)路徑自然參數(shù) 不能夠以 / 開始.
有一個(gè)問題需要注意, 當(dāng)傳遞參數(shù)為空字符串的時(shí)候, 得到路徑其實(shí)是classes文件夾的絕對(duì)路徑, 但當(dāng)傳遞一個(gè)正確的資源路徑相對(duì)字符串時(shí), 得到路徑卻是resources文件夾下的資源路徑.
String name = '';
URL test = this.getClass().getClassLoader().getResource(name);
我的理解是本質(zhì)上是通過此方法獲取的其實(shí)類加載器加載的class字節(jié)碼目錄, 所以使用空字符串會(huì)看到實(shí)際輸出的是classes文件夾絕對(duì)路徑, 當(dāng)傳遞正確的資源路徑的時(shí)候, 代碼層面做轉(zhuǎn)換, 轉(zhuǎn)而獲取與classes文件夾同級(jí)的resources文件夾下的資源.
再看 Class 中的 getResurce 方法
由于這個(gè)方法傳遞參數(shù)是否是以 / 開頭會(huì)產(chǎn)生不同的結(jié)果, 且使用這個(gè)方法也比較容易和 ClassLoader 中的 getResource 方法搞混淆, 所以本文多次強(qiáng)調(diào)傳遞的參數(shù)是否以 / 開始.
首先看傳遞參數(shù)為 '' 和 / 的兩種情況得到的結(jié)果:
使用空字符串:
String name = '';
URL test = this.getClass().getResource(name);
運(yùn)行結(jié)果:
使用 /
String name = '/';
URL test = this.getClass().getResource(name);
運(yùn)行結(jié)果為:
最大的區(qū)別是使用空字符串 '' 獲取的路徑是相對(duì)于包的目錄, 而使用 / 獲取的路徑是類加載器加載class文件的目錄, 這個(gè)和 ClassLoader 的 getResource 方法傳遞 '' 字符串的結(jié)果是一樣的. 所以如果要正確的獲取到資源文件,
那么使用 Class 的 getResource 方法如下:
String name = '/com/mainres/testmain.txt';
URL test = this.getClass().getResource(name);
運(yùn)行結(jié)果:
所以綜上所述, 一個(gè)簡單的防止兩個(gè)方法傳遞參數(shù)搞混淆的記憶方式就是使用 Class 的 getResource 方法需要加 / 而使用 ClassLoader 的 getResource 方法不要加 /.
其實(shí)參考 Class 類中的 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); }
本質(zhì)上講它也是調(diào)用ClassLoader 中的getResource 方法. 其中resolveName 這個(gè)方法對(duì)傳遞的參數(shù)做了轉(zhuǎn)換.
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; }
當(dāng)傳遞的參數(shù)帶有/ 時(shí)候, resolveName 會(huì)將/ 去除后的字符串返回, 最后調(diào)用ClassLoader 中的 getResource 方法.
小結(jié)
本文對(duì)比了一下Class 和 ClassLoader 中的getResource 方法的差異,如果單純從資源的獲取角度來看最終調(diào)用的都是ClassLoader 中的getResource 方法.
簡單記憶即是使用Class 的getResource 方法資源路徑需要加/ 而使用ClassLoader 中的getResource 方法則不需要加/.
以上這篇Java Gradle項(xiàng)目中的資源正確獲取方式就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持好吧啦網(wǎng)。
相關(guān)文章:
1. 前端從瀏覽器的渲染到性能優(yōu)化2. ASP實(shí)現(xiàn)加法驗(yàn)證碼3. 利用CSS3新特性創(chuàng)建透明邊框三角4. 讀大數(shù)據(jù)量的XML文件的讀取問題5. 解析原生JS getComputedStyle6. 無線標(biāo)記語言(WML)基礎(chǔ)之WMLScript 基礎(chǔ)第1/2頁7. css代碼優(yōu)化的12個(gè)技巧8. ASP刪除img標(biāo)簽的style屬性只保留src的正則函數(shù)9. ASP基礎(chǔ)入門第三篇(ASP腳本基礎(chǔ))10. PHP循環(huán)與分支知識(shí)點(diǎn)梳理
