码迷,mamicode.com
首页 > 编程语言 > 详细

Spring源码分析——资源访问利器Resource之接口和抽象类分析

时间:2014-10-10 23:11:24      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   color   io   os   ar   java   for   

  从今天开始,一步步走上源码分析的路。刚开始肯定要从简单着手。我们先从Java发展史上最强大的框架——Spring、、、旗下的资源抽象接口Resource开始吧。

  我看了好多分析Spring源码的,每每一开始就是Spring IOC、AOP、BeanFactory这样的Spring典型模块,实在看厌了,这些暂且留到以后。我的想法是,分析就分析别人没分析过的,或者以不同的角度来分析别人分析过的。

  可能很多用了Spring多年的程序员对Resource都了解有限,毕竟访问资源一般是搭建web工程框架的时候的事情。不过了解它也是非常有好处的。

  这个接口的作用是可以让我们更方便操纵底层资源。因为JDK操纵底层资源基本就是 java.net.URL 、java.io.File 、java.util.Properties这些。取资源基本是根据绝对路径或当前类的相对路径来取。从类路径或Web容器上下文中获取资源的时候也不方便。Resource接口提供了更强大的访问底层资源的能力。

  废话不多说,看源码之前先来看一下Resource的类结构。

一、类结构

bubuko.com,布布扣

一、Resource接口

  如图,Resouce接口并不是一个根接口,它继承了一个简单的父接口 InputStreamSource,这个接口只有一个方法,用以返回一个输入流:

InputStream getInputStream() throws IOException;

  来,直接上Resource接口的源码,中文是我根据英文注释自己翻译的,如下:

public interface Resource extends InputStreamSource {

    boolean exists();      //  资源是否存在

    boolean isReadable();  //  资源是否可读

    boolean isOpen();      //  资源所代表的句柄是否被一个stream打开了

    URL getURL() throws IOException;   //  返回资源的URL的句柄

    URI getURI() throws IOException;   //  返回资源的URI的句柄

    File getFile() throws IOException; //  返回资源的File的句柄

    long contentLength() throws IOException;   //  资源内容的长度

    long lastModified() throws IOException;    //  资源最后的修改时间

    Resource createRelative(String relativePath) throws IOException;   //根据资源的相对路径创建新资源

    String getFilename();  //  资源的文件名

    String getDescription();   //资源的描述

}

   这个没什么好说的,继续!

 

二、抽象类AbstractResource

  对于任何的接口而言,这个直接抽象类是重中之重,里面浓缩了接口的大部分公共实现。翻译后如下:

public abstract class AbstractResource implements Resource {

    public boolean exists() {  //判断文件是否存在,若判断过程产生异常(因为会调用SecurityManager来判断),就关闭对应的流
        try {
            return getFile().exists();
        }
        catch (IOException ex) {
            try {
                InputStream is = getInputStream();  //getInputStream()方法会被子类重写,
                is.close();
                return true;
            }
            catch (Throwable isEx) {
                return false;   
            }
        }
    }

    public boolean isReadable() {  //  直接返回true,可读
        return true;
    }

    public boolean isOpen() {  //  直接返回false,未被打开
        return false;
    }

    public URL getURL() throws IOException {        //  留给子类重写
        throw new FileNotFoundException(getDescription() + " cannot be resolved to URL");
    }

    public URI getURI() throws IOException {   //返回url
        URL url = getURL();
        try {
            return ResourceUtils.toURI(url);     //将url格式化后返回
        }
        catch (URISyntaxException ex) {
            throw new NestedIOException("Invalid URI [" + url + "]", ex);
        }
    }

    public File getFile() throws IOException {     //  留给子类重写
        throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");
    }

    // 这个资源内容长度实际就是资源的字节长度,通过全部读取一遍来判断。这个方法调用起来很占资源啊!
    public long contentLength() throws IOException {   
        InputStream is = this.getInputStream();
        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 {
                is.close();
            }
            catch (IOException ex) {
            }
        }
    }

    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;
    }

    // 这是Resource接口所没有的方法,注释的意思是“返回文件,给时间戳检查”,要求子类重写...
    protected File getFileForLastModifiedCheck() throws IOException {
        return getFile();
    }

    public Resource createRelative(String relativePath) throws IOException {   //  留给子类重写
        throw new FileNotFoundException("Cannot create a relative resource for " + getDescription());
    }

    public String getFilename() {  //  默认返回空(假设资源没有文件名),除非子类重写
        return null;
    }

    @Override
    public String toString() {     //  toString返回文件描述
        return getDescription();
    }

    @Override
    public boolean equals(Object obj) {    //  equals比较的就是2个资源描述是否一样
        return (obj == this ||
            (obj instanceof Resource && ((Resource) obj).getDescription().equals(getDescription())));
    }

    @Override
    public int hashCode() {    //  返回资源描述的HashCode
        return getDescription().hashCode();   
    }

}

 

结论:

  1、增加了一个方法,protected File getFileForLastModifiedCheck() throws IOException,要求子类实现,如果子类未实现,那么直接返回资源文件。这个方法的具体作用,后面再看实现类。

  2、方法 contentLength() ,是一个很比较重量级的方法,它通过将资源全部读取一遍来判断资源的字节数。255字节的缓冲数组来读取。子类一般会重写。(调整一下缓冲数组的大小?)

  3、getDescription() 是这个抽象类唯一没有实现的接口方法,留给子类去实现,资源文件默认的equals()、hashCode() 都通过这个来判断。

  4、InputStreamSource这个祖先接口的唯一方法 getInputStream()也没有被实现,留给子类。

 

三、Resource的子接口ContextResource和WritableResource

  这两个接口继承于Resource,拥有Resource的全部方法。其中,ContextResource接口增加了一个方法:

String getPathWithinContext(); //  返回上下文内的路径  

  这个方法使得它的实现类有了返回当前上下文路径的能力。

 

  WritableResource接口增加了2个方法:

    boolean isWritable();  //  是否可写

    OutputStream getOutputStream() throws IOException; //返回资源的写入流

  这个方法使得它的实现类拥有了写资源的能力。

 

   PS:框架感觉大都是这样,不难,设计模式也运用的不多。却有一种大巧不工、重剑无锋的感觉,因为代码运用真的非常简练。

    分析源码,很大程度上也锻炼了自己的英文文档阅读能力。共勉。

 

Spring源码分析——资源访问利器Resource之接口和抽象类分析

标签:des   style   blog   color   io   os   ar   java   for   

原文地址:http://www.cnblogs.com/zrtqsk/p/4015323.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!