javascript
Spring ClassPathResource详解
????????org.springframework.core.io.ClassPathResource位于Spring核心core下,用以表達(dá)類路徑下的資源。
????????首先簡(jiǎn)要說(shuō)明一下什么是classpath,顧名思義,就是存放*.class類文件的路徑,或者說(shuō)ClassLoader加載類時(shí)為找到 *.class文件的路徑。我們以一個(gè)WEB項(xiàng)目為例,發(fā)布后的目錄結(jié)構(gòu)大致如下:
????????然后以Tomcat為例,看一下WEB項(xiàng)目類加載時(shí)候的目錄,參考 Tomcat Class Loader How-To 中的說(shuō)明:
WebappX — A class loader is created for each web application that is deployed in a single Tomcat instance. All unpacked classes and resources in the /WEB-INF/classes directory of your web application, plus classes and resources in JAR files under the /WEB-INF/lib directory of your web application, are made visible to this web application, but not to other ones.
????????因此,對(duì)于部署在Tomcat上的WEB應(yīng)用來(lái)說(shuō),/WEB-INF/classes和/WEB-INF/lib目錄就是我們所指的classpath。
????????ClassPathResource是org.springframework.core.io.Resource接口的實(shí)現(xiàn)類??梢允褂?strong>ClassLoader或Class類加載資源。支持轉(zhuǎn)換為java.io.File對(duì)象(在Jar文件中的資源除外)。其繼承實(shí)現(xiàn)關(guān)系圖如下:
????????ClasspathResource類的屬性變量和構(gòu)造方法如下:
private final String path;@Nullableprivate ClassLoader classLoader;// 通過(guò)ClassLoader加載資源文件@Nullableprivate Class<?> clazz; // 通過(guò)Class類加載資源文件// 通過(guò)類路徑創(chuàng)建resourcepublic ClassPathResource(String path){...}// 通過(guò)類路徑和給定的ClassLoader創(chuàng)建resourcepublic ClassPathResource(String path, @Nullable ClassLoader classLoader){...}// 通過(guò)類路徑和給定的Class類創(chuàng)建resourcepublic ClassPathResource(String path, @Nullable Class<?> clazz){...}// 通過(guò)類路徑和給定的ClassLoader或Class創(chuàng)建resourceprotected ClassPathResource(String path, @Nullable ClassLoader classLoader, @Nullable Class<?> clazz){...}????????在類繼承關(guān)系中,每個(gè)類定義的方法如下:
| 對(duì)底層資源的抽象描述 比如文件或類路徑資源 | 對(duì)資源接口描述的基礎(chǔ)實(shí)現(xiàn) 預(yù)先實(shí)現(xiàn)特定的行為 | 將URL解析為文件資源引用的抽象基類,尤其對(duì)JBOOS的vfs文件協(xié)議的支持 | 類路徑資源的Resource實(shí)現(xiàn) |
| boolean exists() 判斷該資源是否存在 | public boolean exists() 實(shí)現(xiàn)父接口方法,檢查資源(文件或目錄)File對(duì)象或資源(文件)InputStream對(duì)象是否打開 | public boolean exists() 重寫父類方法,getURL后如果URL的文件協(xié)議是file:、vfsfile:、vfs則返回getFile().exists()直接判斷該文件是否存在,如果非上述文件協(xié)議則嘗試判斷是否網(wǎng)絡(luò)資源,通過(guò)HTTP請(qǐng)求看是否返回HTTP Status-Code=200,如果扔非上述,則嘗試getInputStream().close()看文件流是否可打開 | public boolean exists() 重寫父類方法,判斷是否能獲取到該資源的URL對(duì)象 |
| boolean isReadable() 是否可通過(guò)InputStreamSource.getInputStream()讀取,這里注意返回true仍然可能讀取失敗,但返回false一定是不能讀取 默認(rèn)返回exists() | public boolean isReadable() 實(shí)現(xiàn)父接口方法,該方法在當(dāng)資源存在的情況下始終返回true,返回值與父接口方法中定義的默認(rèn)返回值一致,即返回exists() | public boolean isReadable() 重寫父類方法,getURL后如果URL的文件協(xié)議是file:、vfsfile:、vfs則getFile得到該資源File對(duì)象,判斷該File資源是否非目錄且canRead可讀,如果非上述文件協(xié)議則嘗試調(diào)用網(wǎng)絡(luò)資源,判斷是否可成功調(diào)用且返回內(nèi)容長(zhǎng)度大于0,如果扔非上述,則嘗試getInputStream().close()看文件流是否可打開 | |
| boolean isOpen() 表明該資源是否有打開的stream流,如果返回true則InputStream無(wú)法多次讀取,且讀完之后關(guān)閉流以防止內(nèi)存泄露 默認(rèn)返回false | public boolean isOpen() 實(shí)現(xiàn)父接口方法,與接口方法中定義的默認(rèn)返回值一致,即始終返回false | ||
| boolean isFile() 判斷該文件是否是系統(tǒng)文件中的文件,true值表示(但不保證)可以成功調(diào)用getFile()方法 默認(rèn)返回false | public boolean isFile() 實(shí)現(xiàn)父接口方法,與接口方法中定義的默認(rèn)返回值一致,即始終返回false | public boolean isFile() 重寫父類方法,getURL后如果url為vfs開頭協(xié)議(vfs/vfsfile)則交給VfsResourceDelegate類判斷,如果url為file協(xié)議則返回true | |
| protected boolean isFile(URI uri) 重載isFile方法,根據(jù)指定的URI判斷該資源是否是一個(gè)文件引用,如果URI的scheme以vfs開頭則交給VfsResourceDelegate類判斷,否則判斷如果URI的scheme等于file則返回true | |||
| URL getURL() 返回該資源對(duì)應(yīng)的URL | public URL getURL() 實(shí)現(xiàn)父接口方法,這里假設(shè)資源不能解析為URL,直接返回了FileNotFoundException異常 | public URL getURL() 重寫父類方法,根據(jù)類路徑參數(shù)獲取該資源的URL對(duì)象 | |
| URI getURI() 返回該資源對(duì)應(yīng)的URI | public URI getURI() 實(shí)現(xiàn)父接口方法,基于getURL返回的URL構(gòu)建一個(gè)URI | ||
| File getFile() 返回該資源的File對(duì)象 | public File getFile() 實(shí)現(xiàn)父接口方法,這里假設(shè)資源無(wú)法解析為文件絕對(duì)路徑,直接返回了FileNotFoundException異常 | public File getFile() 重寫父類方法,父類直接返回FileNotFoundException異常,在這里通過(guò)getURL獲取到URL對(duì)象(具體URL由其子類確定,比如ClasspathResource重寫了getURL通過(guò)類加載器獲取到了類路徑資源的URL),如果url為vfs開頭協(xié)議(vfs/vfsfile)則交給VfsResourceDelegate類獲取File對(duì)象,否則通過(guò)得到url獲取File對(duì)象 | |
| protected File getFile(URI uri) 重載getFile方法,根據(jù)指定的URI獲取資源File對(duì)象,如果URI的scheme以vfs開頭則交給VfsResourceDelegate類獲取 | |||
| ReadableByteChannel readableChannel() 默認(rèn)返回Channels.newChannel(getInputStream()) | public ReadableByteChannel readableChannel() 實(shí)現(xiàn)父接口方法,與父接口的默認(rèn)返回值相同 | public ReadableByteChannel readableChannel() 根據(jù)指定的URI調(diào)用FileChannel.open 返回一個(gè)ReadableByteChannel對(duì)象 | |
| long contentLength() 返回該資源內(nèi)容的長(zhǎng)度 | public long contentLength() 根據(jù)getInputStream()返回的InputStream,讀取并計(jì)算資源的內(nèi)容長(zhǎng)度 | public long contentLength() 根據(jù)getURL獲得URL對(duì)象,如果是文件(file/vfsfile/vfs)URL返回文件長(zhǎng)度,否則嘗試網(wǎng)絡(luò)連接獲取資源并返回長(zhǎng)度 | |
| long lastModified() 返回該資源最后一次修改的時(shí)間戳 | public long lastModified() 獲取并返回該資源文件的時(shí)間戳 | public long lastModified() 根據(jù)getURL獲取URL對(duì)象,如果是文件(file/vfsfile/vfs)或歸檔文件(jar/war/zip/vfszip/wsjar)則獲取文件的最后修改時(shí)間戳,否則獲取網(wǎng)絡(luò)連接并獲取最后修改時(shí)間戳 | |
| Resource createRelative(String relativePath) 根據(jù)相對(duì)于該資源的相對(duì)路徑,創(chuàng)建一個(gè)Resource資源,比如classpath資源目錄conf下有A.xml和B.xml,Resource a = new ClassPathResource("conf/A.xml"); 那么在創(chuàng)建b資源的時(shí)候就可以以a為參照Resource b = a.createRelative("B.xml"); | public Resource createRelative(String relativePath) 實(shí)現(xiàn)父接口方法,這里假設(shè)改相對(duì)資源未被創(chuàng)建,直接返回了FileNotFoundException異常 | public Resource createRelative(String relativePath) 重寫父類方法,根據(jù)參照資源的類路徑得到relativePath參數(shù)的真實(shí)classpath路徑,并創(chuàng)建Resource資源對(duì)象 | |
| String getFilename() 返回該資源的文件名,通常是路徑的最后一部分,比如:myfile.txt | public String getFilename() 實(shí)現(xiàn)父接口方法,這里假設(shè)該資源無(wú)文件名,直接返回了null | public String getFilename() 重寫父類方法,根據(jù)classpath截取后面的文件名并返回 | |
| String getDescription() 返回該資源的描述,用于該資源在處理時(shí)的錯(cuò)誤輸出 | public String getDescription() 重寫父類方法,返回格式如class path resource [...]的內(nèi)容 | ||
| protected File getFileForLastModifiedCheck() 獲取用于時(shí)間戳檢查的文件,這里默認(rèn)返回了getFile() | protected File getFileForLastModifiedCheck() 重寫父類方法,擴(kuò)展了父類方法,在getFile之前先判斷url協(xié)議是否為jar/war/zip/vfszip/wsjar,如果是則獲取最外層的文件URL對(duì)應(yīng)的File對(duì)象,比如嵌套在war中的jar文件,則返回war文件File對(duì)象。這里判斷vfs開頭協(xié)議扔交給VfsResourceDelegate類來(lái)處理 | ||
| public boolean equals(Object other) 重寫Object的equals方法,用于比較兩個(gè)Resource的Description是否相同 | public boolean equals(Object other) 重寫Object方法,比較類路徑的值是否相同 | ||
| public int hashCode() 重寫Object的hashCode方法,用于獲取Resource的Description值的hashCode值 | public int hashCode() 重寫Object方法,獲取類路徑classpath的hashCode值 | ||
| public String toString() 重寫Object的toString方法,返回Resource的Description信息 | |||
| public final String getPath() 返回該資源的classpath,構(gòu)造函數(shù)的path參數(shù)經(jīng)過(guò)規(guī)范化處理的結(jié)果 | |||
| public final ClassLoader getClassLoader() 如果指定了Class,則通過(guò)該Class獲取ClassLoader,否則返回屬性變量的ClassLoader參數(shù) | |||
| public InputStream getInputStream() Resource繼承了InputStreamSource接口,在ClassPathResource中得到了具體的實(shí)現(xiàn),根據(jù)資源路徑得到文件流 |
????????在AbstractFileResolvingResource類中由于增加了對(duì)JBOOS的vfs文件協(xié)議的支持,因此包含了一個(gè)`VfsResourceDelegate`內(nèi)部類用于獲取`VfsResource`類型資源對(duì)象,該資源對(duì)象同樣繼承自`AbstractResource`抽象類,并針對(duì)vfs文件的特點(diǎn)對(duì)方法進(jìn)行了重寫。如下: /*** Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime.*/ private static class VfsResourceDelegate {public static Resource getResource(URL url) throws IOException {return new VfsResource(VfsUtils.getRoot(url));}public static Resource getResource(URI uri) throws IOException {return new VfsResource(VfsUtils.getRoot(uri));} }
ClassPathResource的使用:
Resource resource = new ClassPathResource("conf/custom-beans.xml");參數(shù)path應(yīng)在類路徑下能夠被ClassLoader所加載。
????????獲取到了Resource對(duì)象也就等于獲取到了該資源文件,后面可以根據(jù)方法的定義對(duì)文件進(jìn)行相關(guān)操作。
System.out.println(resource.getURL()); System.out.println(resource.getFilename()); System.out.println(resource.getFile().getPath()); // ... ....總結(jié)
以上是生活随笔為你收集整理的Spring ClassPathResource详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: My Sixth-First - 解数独
- 下一篇: Spring中常用注解及其作用(二)