Spring资源抽象Resource

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

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

一、类结构

一、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; //返回资源的写入流

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

四、重要的抽象类AbstractFileResolvingResource

  这个抽象类继承自AbstractResource,重写了AbstractResource的大部分方法。

public abstract class AbstractFileResolvingResource extends AbstractResource {

    @Override
    public File getFile() throws IOException { //  通过资源的URL得到资源本身,是文件就返回文件,否则返回描述
        URL url = getURL();
        if (url.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
            return VfsResourceDelegate.getResource(url).getFile();
        }
        return ResourceUtils.getFile(url, getDescription());
    }

    @Override
    protected File getFileForLastModifiedCheck() throws IOException {  //从<压缩文件地址>中获取文件
        URL url = getURL();
        if (ResourceUtils.isJarURL(url)) {
            URL actualUrl = ResourceUtils.extractJarFileURL(url);
            if (actualUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
                return VfsResourceDelegate.getResource(actualUrl).getFile();
            }
            return ResourceUtils.getFile(actualUrl, "Jar URL");
        }
        else {
            return getFile();
        }
    }

    protected File getFile(URI uri) throws IOException {   //  通过资源uri获取文件
        if (uri.getScheme().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
            return VfsResourceDelegate.getResource(uri).getFile();
        }
        return ResourceUtils.getFile(uri, getDescription());
    }

    @Override
    public boolean exists() {  //判断资源是否存在,如果是文件Url,直接获取文件判断,否则,建立连接来判断。
        try {
            URL url = getURL();
            if (ResourceUtils.isFileURL(url)) {
                // Proceed with file system resolution...
                return getFile().exists();
            }
            else {
                // Try a URL connection content-length header...
                URLConnection con = url.openConnection();
                ResourceUtils.useCachesIfNecessary(con);
                HttpURLConnection httpCon =
                        (con instanceof HttpURLConnection ? (HttpURLConnection) con : null);
                if (httpCon != null) {
                    httpCon.setRequestMethod("HEAD");
                    int code = httpCon.getResponseCode();
                    if (code == HttpURLConnection.HTTP_OK) {
                        return true;
                    }
                    else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
                        return false;
                    }
                }
                if (con.getContentLength() >= 0) {
                    return true;
                }
                if (httpCon != null) {
                    // no HTTP OK status, and no content-length header: give up
                    httpCon.disconnect();
                    return false;
                }
                else {
                    // Fall back to stream existence: can we open the stream?
                    InputStream is = getInputStream();
                    is.close();
                    return true;
                }
            }
        }
        catch (IOException ex) {
            return false;
        }
    }

    @Override
    public boolean isReadable() {  //  是否可读
        try {
            URL url = getURL();
            if (ResourceUtils.isFileURL(url)) {
                // Proceed with file system resolution...
                File file = getFile();
                return (file.canRead() && !file.isDirectory());
            }
            else {
                return true;
            }
        }
        catch (IOException ex) {
            return false;
        }
    }

    @Override
    public long contentLength() throws IOException {
        URL url = getURL();
        if (ResourceUtils.isFileURL(url)) {
            // Proceed with file system resolution...
            return getFile().length();
        }
        else {
            // Try a URL connection content-length header...
            URLConnection con = url.openConnection();
            ResourceUtils.useCachesIfNecessary(con);
            if (con instanceof HttpURLConnection) {
                ((HttpURLConnection) con).setRequestMethod("HEAD");
            }
            return con.getContentLength();
        }
    }

    @Override
    public long lastModified() throws IOException {
        URL url = getURL();
        if (ResourceUtils.isFileURL(url) || ResourceUtils.isJarURL(url)) {
            // Proceed with file system resolution...
            return super.lastModified();
        }
        else {
            // Try a URL connection last-modified header...
            URLConnection con = url.openConnection();
            ResourceUtils.useCachesIfNecessary(con);
            if (con instanceof HttpURLConnection) {
                ((HttpURLConnection) con).setRequestMethod("HEAD");
            }
            return con.getLastModified();
        }
    }

    /**
     * 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));
        }
    }

}

  

这个抽象类的子类都需要重写继承自AbstractResource的getURL()方法。因为绝大多数方法都依赖这个方法,进行资源在url上的操作。

  所以在查看资源情况的时候,需要根据url建立连接来查看。

来源: http://www.cnblogs.com/zrtqsk/p/4015323.html

时间: 2024-10-31 22:14:22

Spring资源抽象Resource的相关文章

Spring讲解-----------资源(resource)

4.1.1  概述 在日常程序开发中,处理外部资源是很繁琐的事情,我们可能需要处理URL资源.File资源资源.ClassPath相关资源.服务器相关资源(JBoss AS 5.x上的VFS资源)等等很多资源.因此处理这些资源需要使用不同的接口,这就增加了我们系统的复杂性:而且处理这些资源步骤都是类似的(打开资源.读取资源.关闭资源),因此如果能抽象出一个统一的接口来对这些底层资源进行统一访问,是不是很方便,而且使我们系统更加简洁,都是对不同的底层资源使用同一个接口进行访问. Spring 提供

攻城狮在路上(贰) Spring(三)--- Spring 资源访问利器Resource接口

Spring为了更好的满足各种底层资源的访问需求.设计了一个Resource接口,提供了更强的访问底层资源的能力.Spring框架使用Resource装载各种资源,包括配置文件资源.国际化属性文件资源等.一.Resource接口的主要方法有: boolean exists():资源是否存在. boolean isOpen():资源是否打开. URL getURL():如果底层资源可以表示为URL,该方法返回对应的URL对象. File getFile():如果底层资源对应一个文件,该方法返回对应

【转载】Spring加载resource时classpath*:与classpath:的区别

免责声明:     本文转自网络文章,转载此文章仅为个人收藏,分享知识,如有侵权,请联系博主进行删除.     原文作者:kyfxbl     原文地址: spring配置中classpath和classpath*的区别   在spring配置文件里,可以用classpath:前缀,来从classpath中加载资源  比如在src下有一个jdbc.properties的文件,可以用如下方法加载: <bean id="propertyConfigurer" class="

spring资源读取

spring中对资源的读取提供有自己的新方案,比传统IO操作更加智能方便. 对于所有的资源处置,spring提供了Resource接口,该接口中的方法都是通过其父接口InputStreamSource实现的.该接口有四个常用子类,通过这四个子类实现资源获取: ClassPathResource.FileSystemResource.UrlResource.ByteArrayResource. 这四个子类中最重要的是ClassPathResource,是用来读取classpath下的资源文件: 此

Spring Cache抽象详解

缓存简介 缓存,我的理解是:让数据更接近于使用者:工作机制是:先从缓存中读取数据,如果没有再从慢速设备上读取实际数据(数据也会存入缓存):缓存什么:那些经常读取且不经常修改的数据/那些昂贵(CPU/IO)的且对于相同的请求有相同的计算结果的数据.如CPU--L1/L2--内存--磁盘就是一个典型的例子,CPU需要数据时先从L1/L2中读取,如果没有到内存中找,如果还没有会到磁盘上找.还有如用过Maven的朋友都应该知道,我们找依赖的时候,先从本机仓库找,再从本地服务器仓库找,最后到远程仓库服务器

转:Spring Cache抽象详解

缓存简介 缓存,我的理解是:让数据更接近于使用者:工作机制是:先从缓存中读取数据,如果没有再从慢速设备上读取实际数据(数据也会存入缓存):缓存什么:那些经常读取且不经常修改的数据/那些昂贵(CPU/IO)的且对于相同的请求有相同的计算结果的数据.如CPU--L1/L2--内存--磁盘就是一个典型的例子,CPU需要数据时先从L1/L2中读取,如果没有到内存中找,如果还没有会到磁盘上找.还有如用过Maven的朋友都应该知道,我们找依赖的时候,先从本机仓库找,再从本地服务器仓库找,最后到远程仓库服务器

WPF 之 资源(Resource)

1.什么叫WPF的资源(Resource)? 资源是保存在可执行文件中的一种不可执行数据.在WPF的资源中,几乎可以包含图像.字符串等所有的任意CLR对象,只要对象有一个默认的构造函数和独立的属性. 也就是说,应用程序中非程序代码的内容,比如点阵图.颜色.字型.动画/影片档以及字符串常量值,可将它们从程序中独立出来,单独包装成"资源(Resource)". 包含两种资源:静态资源(Static Resource),动态资源(Dynamic Resources).这两者的区别是: [1]

spring下应用@Resource, @Autowired 和 @Inject注解进行依赖注入的差

代码: 为了探寻  '@Resource', '@Autowired', 和'@Inject'如何解决依赖注入中的问题,我创建了一个"Party"接口,和它的两个实现类"Person","Organization".这样我就可以在注入Bean的时候不必使用具体类型(指使用接口类型即可).这样做也方便我研究当一个接口有多个实现类与之匹配的时候Spring是如何解决依赖注入的不确定性的. public interface Party {} packa

[asp.net webfrom+spring.net Error] Resource handler for the &#39;web&#39; protocol is not defined.

错误提示: Resource handler for the 'web' protocol is not defined. 解决方案: 修改web.config如下: <system.web> <httpHandlers> <add verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web"/> </htt