spring源碼分析-core.io包里面的類


前些日子看《深入理解javaweb開發》時,看到第一章java的io流,發覺自己對io流真的不是很熟悉。然后看了下JDK1.7中io包的一點點代碼,又看了org.springframework.core.io包的一些類和組織方式,當作是學習吧。總結一下。

先掛下spring.core.io包的類圖,其中接口是方框表示,抽象類帶了abstract前綴,剩下那個兩個框重貼的則代表實現類。沒怎么划過類圖,如果有好的畫類圖工具請推薦給我。

畫得不好的地方就見諒了。注:以下源碼匹配的是spring-core-4.1.6Release.jar里面的org.springframework.core.io包。

 

先看處於最上層的接口,叫InputStreamSource,里面只有一個抽象方法

接下是resources,這個接口我們一般都會用到,貼源碼:

public interface Resource extends InputStreamSource {

    boolean exists();//文件是否存在
    
    boolean isReadable();//是否可讀

    boolean isOpen();//資源是否被一個inputstream打開,如果已被打開,則不允許其他流再打開

    URL getURL() throws IOException;//獲取資源url路徑,當不能以url描述時拋出ioException異常

    
    URI getURI() throws IOException;//獲取資源uri路徑,當不能以url描述時拋出ioException異常

    File getFile() throws IOException;//獲取file,file在IO流中僅僅是一個指向作用

    long contentLength() throws IOException;//資源的字節長度,可以拿來算資源的大小

    long lastModified() throws IOException;//資源最后修改時間

    Resource createRelative(String relativePath) throws IOException;//根據資源相對路徑創建資源

    String getFilename();//返回文件名

    String getDescription();//資源描述

}

 

后面是abstractResource,這是個挺重要的類,主要是對resource接口的基本實現,

public abstract class AbstractResource implements Resource {

    @Override
    public boolean exists() {
        //看是否能在硬盤上找到
        try {
            return getFile().exists();
        }
        catch (IOException ex) {
            // 試一下能不能打開輸出流
            try {
                InputStream is = getInputStream();
                is.close();
                return true;
            }
            catch (Throwable isEx) {
                return false;
            }
        }
    }

    /**
     * 一般都是可讀的,所以默認方法是true
     */
    @Override
    public boolean isReadable() {
        return true;
    }

    /**
     * 默認值是false,沒有inputStream來讀時的默認狀態
     */
    @Override
    public boolean isOpen() {
        return false;
    }

    /**
     * url這個屬性一般只出現在web的IO資源中,網絡resource需要override這個方法,其他類型資源敢訪問這個方法,拋個異常給他
     */
    @Override
    public URL getURL() throws IOException {
        throw new FileNotFoundException(getDescription() + " cannot be resolved to URL");
    }

    
    @Override
    public URI getURI() throws IOException {
        URL url = getURL();
        try {
                        //url可以轉成uri,uri不能轉url
            return ResourceUtils.toURI(url);
        }
        catch (URISyntaxException ex) {
            throw new NestedIOException("Invalid URI [" + url + "]", ex);
        }
    }

    /**
     * JDK的File類都是返回絕對路徑的File,當一個資源沒有絕對路徑時,拋個異常給它沒毛病
     */
    @Override
    public File getFile() throws IOException {
        throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");
    }

    /**
     * inputStream讀取byte[]字節流,並返回該數組的長度,相當於把文件讀了一次
     */
    @Override
    public long contentLength() throws IOException {
        InputStream is = this.getInputStream();
                //Assert應該是叫斷言
        Assert.state(is != null, "resource input stream must not be null");
        try {
            long size = 0;
            byte[] buf = new byte[255];
            int read;
            while ((read = is.read(buf)) != -1) {
                size += read;
            }
            return size;
        }
        finally {
            try {
                              //一定要在finally中關閉流
                is.close();
            }
            catch (IOException ex) {
            }
        }
    }

    /**
     * 返回getFileForLastModifiedCheck().lastModified()的值,該職為0L,拋個異常給他沒毛病
     */
    @Override
    public long lastModified() throws IOException {
        long lastModified = getFileForLastModifiedCheck().lastModified();
        if (lastModified == 0L) {
            throw new FileNotFoundException(getDescription() +
                    " cannot be resolved in the file system for resolving its last-modified timestamp");
        }
        return lastModified;
    }

    /**
     * 調用getFile方法
     */
    protected File getFileForLastModifiedCheck() throws IOException {
        return getFile();
    }

    /**
     * 直接假定相對資源創建不了,再拋個異常給他
     */
    @Override
    public Resource createRelative(String relativePath) throws IOException {
        throw new FileNotFoundException("Cannot create a relative resource for " + getDescription());
    }

    /**
     * 又是一個假定,假定filename文件名為null
     */
    @Override
    public String getFilename() {
        return null;
    }

    /**
     * 很簡單,不解釋
     */
    @Override
    public String toString() {
        return getDescription();
    }

    /**
     * 判斷兩文件是否相等
     */
    @Override
    public boolean equals(Object obj) {
        return (obj == this ||
            (obj instanceof Resource && ((Resource) obj).getDescription().equals(getDescription())));
    }

    /**
     * 返回hashCode
     */
    @Override
    public int hashCode() {
        return getDescription().hashCode();
    }

}
    

至於其他實現類其實都是在接口和抽象類的基礎上去拓展,所以我並不是讀得很仔細,先這樣子吧。

小總結:其實為什么要分好幾層去繼承剛開始我是很不懂的,后面看了源代碼和小伙伴的博文后便豁然開朗了。

1.resources是高度抽象的接口,里面是對所有資源文件的具體方法抽象,但是並不是每個資源都有這個抽象里面的所有方法,所以abstractResource對其進行了一般的實現,

對於一些並不是所有的Resources都會有方法,例如非網絡資源沒有url和uri屬性,默認方法就直接拋異常了,簡單粗暴。舉個栗子,不是所有的動物都會游泳,一只豬想游泳,先拋個異常給豬接着先。

2.resources里面有isOpen(),isReadAble()接口,這是個小技巧吧,類似與模版方法模式的鈎子方法,也是很值得我們學習的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM