Sprint資源訪問

俺就不起網名發表於2018-08-21

目錄

 

一、資源抽象介面

1、傳統java中的資源載入

2、Spring中的Resource介面

二、資源載入

1、資源地址表示式

2、資源載入器

三、總結


一、資源抽象介面

1、傳統java中的資源載入

通過ClassLoader類載入器進行的。程式碼如下:

Thread.currentThread().getContextClassLoader().getResource("com/demo/SimpleJava.class");
SimpleJava.class.getClassLoader().getResource("com/demo/SimpleJava.class");
ClassLoader.getSystemResource("com/demo/SimpleJava.class");
SimpleJava.class.getResource("SimpleJava.class");

每個類載入器載入資源時,都有自己固定的位置,也就是例項化類載入器時傳遞的url,相當於類載入器載入的資源的倉庫,也只會在自己的的倉庫中尋找資源,而classPath下的資源,都是AppClassLoader類進行載入。 

對於通過SimpleJava.class.getResource進行的資源載入,我們可以通過分析原始碼:

//這是class類中進行資源載入的方法
public java.net.URL getResource(String name) {
    name = resolveName(name); //通過解析資源名稱,如果是以/開頭,會在classpath下找尋,name必須為包含全限定名稱的路徑。
    //上面的例子中SimpleJava.class.getResource("SimpleJava.class")的路徑可以換成:/com/demo/SimpleJava.class,如果不是以/開頭,則會在相對於SimpleJava.class的目錄下找尋。
    ClassLoader cl = getClassLoader0();
    if (cl==null) {
        return ClassLoader.getSystemResource(name);
    }
    return cl.getResource(name);
}

2、Spring中的Resource介面

傳統的Java資原始檔的訪問通過JDK中的File、URL類難以滿足各種不同需求的資源載入,這裡有Spring中設計的org.springframework.core.io.Resource介面提供更加強大的訪問底層資源的能力。

下面是Resource介面的主要方法:

boolean exists():資源是否存在;
boolean isOpen():資源是否開啟;
URL getURL() throws IOException:如果底層資源可以表示成URL,該方法返回對應的URL物件;
File getFile() throws IOException:如果底層資源對應一個檔案,該方法返回對應的File物件;
InputStream getInputStream() throws IOException:返回資源對應的輸入流;

Resource具體實現類如下:

ByteArrayResource:二進位制陣列表示的資源;
ClassPathResource:類路徑下的資源,資源以相對於類路徑的方式表示;
FileSystemResource:檔案系統資源,資源以檔案系統路徑的方式表示;
InputStreamResource:以輸入流返回表示的資源;
ServletContextResource:為訪問訪問Web容器上下文中的資源而設計的類,負責以相對於Web應用程式根目錄的路徑載入資源,它支援以流和URL的方式訪問,在WAR解包的情況下,也可以通過File的方式訪問,還可以直接從JAR包中訪問資源;
URLResource:Url封裝了java.net.URL,它使使用者能夠訪問任何可以通過URL表示的資源,如檔案系統的資源、HTTP資源、FTP資源;
PathResource:Spring4.0提供的讀取資原始檔的新類。Path封裝了java.net.URL、java.nio.file.Path、檔案系統資源,它使使用者能夠訪問任何可以同喲URL、Path、系統檔案路徑表示的資源,如檔案系統的資源、Http資源、FTP資源;

如下分別通過FileSystemResource和ClassPathResource訪問同一個檔案資源:

/**
     * Sping獲取資源的介面
     * 繼承的介面有:WritableResource
     * 實現類有:
     * PathResource
     * ClassPathResource
     * FileSystemResource等
     */
    @Test
    public void test_resource() throws IOException {
        //使用系統檔案路徑方式載入資源
        //WritableResource介面繼承介面Resource,新增了 isWritable/getOutputStream 方法
        String filePath = "/Users/admin/spr-mybatis-web/src/main/resources/note/note.txt";
        WritableResource res1 = new PathResource(filePath);

        //使用類路徑方式載入資源
        Resource res2 = new ClassPathResource("note/note.txt");

        //使用WritableResource介面讀取資原始檔
        OutputStream stream1 = res1.getOutputStream();
        stream1.write("這個是測試".getBytes());
        stream1.close();

        //使用Resource介面讀取資源
        InputStream ins1 = res1.getInputStream();
        InputStream ins2 = res2.getInputStream();

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int i;
        while ((i = ins1.read()) != -1) {
            bos.write(i);
        }
        System.out.println(bos.toString());
        System.out.println(res1.getFilename());
        System.out.println(res2.getFilename());
    }

獲取到資源後,可以通過getFileName()獲取方法名,通過getFile()獲取資源對應的File檔案,通過getInputStream()直接獲取檔案的輸入流,還可通過createRelative(String relativePath)在資源相對地址上建立新的檔案。

如下是在Web應用中通過ServletContextResource以相對於Web應用根目錄的方式訪問檔案資源:

Resource res3 = new ServletContextResource(application,"/WEB-INF/classes/conf/file1.txt");

可以通過EncodedResource對資源進行編碼,保證資源內容操作的正確性,如下:

Resource res = new ClassPathResource("conf/file1.txt");
EncodedResource encRes = new EncodedResource(res,"UTF-8");
String content  = FileCopyUtils.copyToString(encRes.getReader());
System.out.println(content); 

二、資源載入

為了訪問不同型別的資源,必須使用相應的Resorce實現類,這是比較麻煩的,spring提供了一個強大的載入資源的機制,能夠自動識別不同的資源型別。

1、資源地址表示式

地址字首 示例 對應的資源型別
classpath: classpath:com/bean/bean.xml 表示從類路徑載入資源,classpath:和classpath:/是等價的,都是相對於類的根路徑。資原始檔可以在標準的檔案系統中,也可以在jar或zip的類包中
file: file:/com/bean/bean.xml 使用UrlResource從檔案系統目錄中裝載資源,可採用絕對或相對路徑
http:// http://www.csdn.bean.xml 使用UrlResource從Web伺服器中裝載資源
ftp:// ftp://www.csdn.bean.xml 使用UrlResource從FTP伺服器中裝載資源
沒有字首 com/bean/bean.xml 根據ApplicationContext的具體實現類採用對應型別的Resource

其中,classpath:和classpath*:的區別在於classpath*:會掃描所有類路徑下出現的資源,而classpath只會在第一個載入的包下查詢,即就是隻載入一個資原始檔。

匹配風格資源地址支援3種:

?:匹配檔案中的一個字元
* :匹配檔案中的任意字元
** :匹配多層路徑
如:file:/com/bean/bea?.xml

2、資源載入器

Spring定義了一套資源載入的介面,並提供了實現類。

2-1、Resource介面

位於包 org.springframework.core.io 下,提供了一些基本方法,如 exists()/getResource()等方法

2-2、ResourcePatternResolver介面

位於包 org.springframework.core.io.support 下,繼承了介面ResourceLoader,增加了Resource[] getResources(String var1)方法,可以看出相對與ResourceLoader介面而言增加了批量載入檔案方法。新增了資源匹配模式表示式,但不支援匹配風格地址載入資源。

2-3、PathMatchingResourcePatternResolver類

位於包 org.springframework.core.io.support 下,實現了介面 ResourcePatternResolver。新增了支援匹配風格地址載入資源。

具體程式碼如下:

    ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    Resource[] resources = resourcePatternResolver.getResources("classpath*:note/not?.txt");
    for(Resource resource:resources){
       System.out.println(resource.getFilename());
    }

三、總結

1、傳統java中的資源載入,是通過類載入器進行獲取資源;

2、Spring獲取資源提供了Resource介面,該介面提供了獲取資源的及其相關方法,並針對不同資源獲取方式提供了不同的實現類;

3、為了訪問不同型別的資源,必須使用相應的Resorce實現類,這是比較麻煩的,spring提供了一個強大的載入資源的機制,能夠自動識別不同的資源型別。Spring為其提供了資源表示式和資源載入器介面和實現類。

 

 

相關文章