8.Spring之Resource(1)
  Op9yysgqYUmV 2023年11月02日 65 0


概述

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

Spring 提供一个Resource接口来统一这些底层资源一致的访问,而且提供了一些便利的接口,从而能提供我们的生产力。

Resource接口

Spring的Resource接口代表底层外部资源,提供了对底层外部资源的一致性访问接口。

public interface InputStreamSource {
    InputStream getInputStream() throws IOException;
}

public interface Resource extends InputStreamSource {
    boolean exists();
    boolean isReadable();
    boolean isOpen();
    URL getURL() throws IOException;
    URI getURI() throws IOException;
    File getFile() throws IOException;
    long contentLength() throws IOException;
    long lastModified() throws IOException;
    Resource createRelative(String relativePath) throws IOException;
    String getFilename();
    String getDescription();
}

1)InputStreamSource接口解析:

getInputStream:每次调用都将返回一个新鲜的资源对应的java.io. InputStream字节流,调用者在使用完毕后必须关闭该资源。

2)Resource接口继承InputStreamSource接口,并提供一些便利方法:

  • exists:返回当前Resource代表的底层资源是否存在,true表示存在。
  • isReadable:返回当前Resource代表的底层资源是否可读,true表示可读。
  • isOpen:返回当前Resource代表的底层资源是否已经打开,如果返回true,则只能被读取一次然后关闭以避免资源泄露;常见的Resource实现一般返回false。
  • getURL:如果当前Resource代表的底层资源能由java.util.URL代表,则返回该URL,否则抛出IOException。
  • getURI:如果当前Resource代表的底层资源能由java.util.URI代表,则返回该URI,否则抛出IOException。
  • getFile:如果当前Resource代表的底层资源能由java.io.File代表,则返回该File,否则抛出IOException。
  • contentLength:返回当前Resource代表的底层文件资源的长度,一般是值代表的文件资源的长度。
  • lastModified:返回当前Resource代表的底层资源的最后修改时间。
  • createRelative:用于创建相对于当前Resource代表的底层资源的资源,比如当前Resource代表文件资源
  • “d:/test/”则createRelative(“test.txt”)将返回表文件资源“d:/test/test.txt”Resource资源。
  • getFilename:返回当前Resource代表的底层文件资源的文件路径,比如File资源“file://d:/test.txt”将返回“d:/test.txt”,而URL资源http://www.baidu.com将返回“”,因为只返回文件路径。
  • getDescription:返回当前Resource代表的底层资源的描述符,通常就是资源的全路径(实际文件名或实际URL地址)。

Resource接口提供了足够的抽象,足够满足我们日常使用。而且提供了很多内置Resource实现:

ByteArrayResource、InputStreamResource 、FileSystemResource 、UrlResource 、ClassPathResource、ServletContextResource、VfsResource等。

内置Resource实现

1、ByteArrayResource

ByteArrayResource代表byte[]数组资源,对于“getInputStream”操作将返回一个ByteArrayInputStream。

首先让我们看下使用ByteArrayResource如何处理byte数组资源:

public void testByteArrayResource() {
    Resource resource = new ByteArrayResource("Hello World!".getBytes());
    if(resource.exists()) {
        dumpStream(resource);
    }
}

接着看下dumpStream()实现:

private void dumpStream(Resource resource) {
    InputStream is = null;
    try {
        //1.获取文件资源
        is = resource.getInputStream();
        //2.读取资源
        byte[] descBytes = new byte[is.available()]; 
        is.read(descBytes);
        System.out.println(new String(descBytes));
    } catch (IOException e) {
        e.printStackTrace();
    }
    finally {
        try {
            //3.关闭资源
            is.close();
        } catch (IOException e) {
        }
    }
}

dumpStream方法简单定义了访问流的三步:打开资源、读取资源、关闭资源,所以dumpStream可以再进行抽象从而能在自己项目中使用;byteArrayResourceTest测试方法,也定义了基本步骤:定义资源、验证资源存在、访问资源。

ByteArrayResource可多次读取数组资源,即isOpen ()永远返回false。

2、InputStreamResource

InputStreamResource代表java.io.InputStream字节流,对于“getInputStream ”操作将直接返回该字节流,因此只能读取一次该字节流,即“isOpen”永远返回true。

@Test
public void testInputStreamResource() {
    ByteArrayInputStream bis = new ByteArrayInputStream("Hello World!".getBytes());
    Resource resource = new InputStreamResource(bis);
    if (resource.exists()) {
        dumpStream(resource);
    }
    System.out.println(resource.isOpen());
}

3、FileSystemResource

FileSystemResource代表java.io.File资源,对于“getInputStream ”操作将返回底层文件的字节流,“isOpen”将永远返回false,从而表示可多次读取底层文件的字节流。

看下测试代码:

@Test
public void testFileResource() {
    File file = new File("d:/test.txt");
    Resource resource = new FileSystemResource(file);
    if(resource.exists()) {
        dumpStream(resource);
    }
    Assert.assertEquals(false, resource.isOpen());
}

注意由于“isOpen”将永远返回false,所以可以多次调用dumpStream(resource)。

4、 ClassPathResource

ClassPathResource代表classpath路径的资源,将使用ClassLoader进行加载资源。classpath资源存在于类路径中的文件系统中或jar包里,且“isOpen”永远返回false,表示可多次读取资源。ClassPathResource加载资源替代了Class类和ClassLoader类的“( name)”和“( name)”两个加载类路径资源方法,提供一致的访问方式。

ClassPathResource提供了三个构造器:

  • public ClassPathResource(String path):使用默认的ClassLoader加载“path”类路径资源;
  • public ClassPathResource(String path, ClassLoader classLoader):使用指定的ClassLoader加载“path”类路径资源;
  • public ClassPathResource(String path, Class<?> clazz):使用指定的类加载“path”类路径资源,将加载相对于当前类的路径的资源;

写几个例子说明一下吧:

/**
     * 使用默认的加载器加载资源,将加载当前ClassLoader类路径上相对于根路径的资源
     * @throws IOException
     */
    @Test
    public void testClasspathResourceByDefaultClassLoader() throws IOException {
        Resource resource = new ClassPathResource("test1.properties");
        if (resource.exists()) {
            dumpStream(resource);
        }
        System.out.println("path:" + resource.getFile().getAbsolutePath());
        Assert.assertEquals(false, resource.isOpen());
    }

    /**
     * 使用指定的ClassLoader进行加载资源,将加载指定的ClassLoader类路径上相对于根路径
     * 的资源
     * @throws IOException
     */
    @Test
    public void testClasspathResourceByClassLoader() throws IOException {
//        ClassLoader loader = Thread.currentThread().getContextClassLoader();
//          System.out.println(loader.getResource("").getPath());
        ClassLoader cl = this.getClass().getClassLoader();
        Resource resource = new ClassPathResource("test1.properties", cl);
        if (resource.exists()) {
            dumpStream(resource);
        }
        System.out.println("path:" + resource.getFile().getAbsolutePath());
        Assert.assertEquals(false, resource.isOpen());
    }

    /**
     * 使用指定的类进行加载资源,将尝试加载相对于当前类的路径的资源
     * @throws IOException
     */
    @Test
    public void testClasspathResourceByClass() throws IOException {
        Class clazz = this.getClass();
        Resource resource1 = new ClassPathResource("/test1.properties", clazz);
        if (resource1.exists()) {
            dumpStream(resource1);
        }
        System.out.println("path:" + resource1.getFile().getAbsolutePath());
        Assert.assertEquals(false, resource1.isOpen());

        Resource resource2 = new ClassPathResource("/test1.properties", this.getClass());
        if (resource2.exists()) {
            dumpStream(resource2);
        }
        System.out.println("path:" + resource2.getFile().getAbsolutePath());
        Assert.assertEquals(false, resource2.isOpen());

    }

    /**
     * 加载jar包里的资源,首先在当前类路径下找不到,最后才到Jar包里找,而且在第一个Jar
     * 包里找到的将被返回
     * @throws IOException
     */
    @Test
    public void testClasspathResourceFromJar() throws IOException {
        Resource resource = new ClassPathResource("overview.html");
        if (resource.exists()) {
            dumpStream(resource);
        }
        System.out.println("path:" + resource.getURL().getPath());
        Assert.assertEquals(false, resource.isOpen());

    }

如果当前类路径包含“overview.html”,在项目的“resources”目录下,将加载该资源,否则将加载Jar包里的“overview.html”,而且不能使用“resource.getFile()”,应该使用“resource.getURL()”,因为资源不存在于文件系统而是存在于jar包里,URL类似于“file:/C:/.../*.jar!/overview.html”。

类路径一般都是相对路径,即相对于类路径或相对于当前类的路径,因此如果使用“/test1.properties”带前缀“/”的路径,将自动删除“/”得到“test1.properties”。

5、UrlResource

UrlResource代表URL资源,用于简化URL资源访问。“isOpen”永远返回false,表示可多次读取资源。

UrlResource一般支持如下资源访问:

http:通过标准的http协议访问web资源,如new UrlResource(“http://地址”);

ftp:通过ftp协议访问资源,如new UrlResource(“ftp://地址”);

file:通过file协议访问本地文件系统资源,如new UrlResource(“file:d:/test.txt”);

/**
 * 使用UrlResource简化URL资源访问
 * @throws IOException
 */
@Test
public void testUrlResource() throws IOException {
    Resource resource = new UrlResource("file:d:/test.txt");
    if (resource.exists()) {
        dumpStream(resource);
    }
    System.out.println("path:" + resource.getURL().getPath());
    Assert.assertEquals(false, resource.isOpen());

    Resource resource2 = new UrlResource("http://www.baidu.com");
    if (resource2.exists()) {
        dumpStream(resource2);
    }
    System.out.println("path:" + resource2.getURL().getPath());
    Assert.assertEquals(false, resource2.isOpen());

}

6 ServletContextResource

ServletContextResource代表web应用资源,用于简化servlet容器的ServletContext接口的getResource操作和getResourceAsStream操作;

7 VfsResource

VfsResource代表Jboss 虚拟文件系统资源。

Jboss VFS(Virtual File System)框架是一个文件系统资源访问的抽象层,它能一致的访问物理文件系统、jar资源、zip资源、war资源等,VFS能把这些资源一致的映射到一个目录上,访问它们就像访问物理文件资源一样,而其实这些资源不存在于物理文件系统。

 

参考:



http://sishuok.com/forum/blogPost/list/0/2455.html

 

 

 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
Op9yysgqYUmV