Resource体系

Resource

在Spring中,对资源进行了抽象,从而屏蔽了资源类型和来源的区别,使得内部对于操作这些资源的API更加统一。下图为Spring中Resource的继承体系图:

Resource继承关系图

根据继承关系图可以看到,整个Resource体系中,进行了一定层级的抽象,通过顶层的借口定义资源常见的操作,然后给出一个通用的抽象实现,最后各个不同类型的资源各自实现各自特殊的处理方法。

最顶层的Resource接口继承自InputStreamSource接口,而InputStreamSource接口中仅定义了一个方法:getInputStream。凡是可以获取输入流的资源都可以是一个InputStreamSource类型。而对于大多数资源文件来说,不一定可写但一般是可读的。因此这里专门为可写的资源类型定义了WritableResource接口,此接口中定义了两个和写操作相关的方法:

  • isWritable
  • getOutputStream

可写的资源一般也包含可读资源的各种特性,因此WritableResource接口继承自Resource接口。在Resource接口中定义了一些通用的方法:

public interface Resource extends InputStreamSource {
   

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

    // 判断资源是否可读,只有在返回true的时候,getInputStream方法才可用
    boolean isReadable();

    // 判断资源是否已打开,如果已打开则资源不能多次读写,资源应该在读完成之后关闭。
    boolean isOpen();

    // 获取资源对象的URL,如果该资源不能表示为URL形式则抛出异常
    URL getURL() throws IOException;

    // 获取资源对象的URI,如果该资源不能表示为URI形式则抛出异常
    URI getURI() throws IOException;

    // 获取资源的File表示对象,如果资源不能表示为File对象则抛出异常
    File getFile() throws IOException;

    // 获取资源内容的长度,如果资源无法解析则抛出异常
    long contentLength() throws IOException;

    // 获取资源最后修改时间戳,如果资源无法解析则抛出异常
    long lastModified() throws IOException;

    // 相对当前资源创建新的资源对象,如果相对的资源无法解析则抛出异常
    Resource createRelative(String relativePath) throws IOException;

    // 获取当前资源的文件名,如果当前资源没有文件名则返回null
    String getFilename();

    // 获取当对资源的描述信息
    String getDescription();
}

Resource接口中定义的方法,并不需要每一种实际资源类型都必须实现,各个实际资源类型根据自身的情况决定要实现哪些方法。例如基于文件的资源一般会实现getFile方法,而不是基于文件的资源则一般不实现getFile方法。

在具体资源实现之前,Spring还提供了一个抽象的公共实现AbstractResource,在AbstractResource中实现一些跟资源类型无关的通用逻辑,和底层资源有关的则留给具体的资源类型去实现。

public abstract class AbstractResource implements Resource {
   

    public boolean exists() {
        // Try file existence: can we find the file in the file system?
        try {
            return getFile().exists();
        } catch (IOException ex) {
            // Fall back to stream existence: can we open the stream?
            try {
                InputStream is = getInputStream();
                is.close();
                return true;
            } catch (Throwable isEx) {
                return false;
            }
        }
    }

    public boolean isReadable() {
        return true;
    }

    public boolean isOpen() {
        return false;
    }

    public URL getURL() throws IOException {
        // 默认认为资源无法表示为URL,子类可覆写此方法
        throw new FileNotFoundException(getDescription() + " cannot be resolved to URL");
    }

    public URI getURI() throws IOException {
        URL url = getURL();
        try {
            // 通过getURL方法的返回值来进行转换
            return ResourceUtils.toURI(url);
        } catch (URISyntaxException ex) {
            throw new NestedIOException("Invalid URI [" + url + "]", ex);
        }
    }

    public File getFile() throws IOException {
        // 默认认为资源无法表示为File对象,子类可覆写
        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 {
            // 默认实现为读取inputStream中的所有数据来获取长度
            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 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值