Spring Resource接口进行资源访问

前言

        什么是资源?我们已知Spring中有很多xml配置文件,同时还可能自建各种properties资源文件,还有可能进行网络交互,首发各种文件、二进制流等。粗略可分为:URL资源、File资源、ClassPath相关资源、服务器相关资源(JBoss AS 5.x上的VFS资源)。Spring把这些文件、二进制流统称为资源。程序对这些资源的访问,就叫做资源访问。

        J2SE中,有些处理资源文件的标准API,例如InputStream等文件IO和java.net.URL。但因为并非专门为Web服务设计,所以对于Spring服务,这些工具类显得比较底层。若直接使用这些方法,需要编写比较多的额外代码,例如前期文件存在判断、相对路径变绝对路径等。

        处理资源文件步骤都很类似(打开资源、读取资源、关闭资源),所以若抽象出一个统一的接口来对这些底层资源进行统一访问,用起来就十分方便。对不同的底层资源都实现同一个接口,重写方法时再实现不同的处理。 这个接口就是Spring提供的Resource接口



一. Resource接口 

Spring的Resource接口继承InputStreamSource。

public interface Resource extends InputStreamSource {
}


InputStreamSource接口方法: 
● getInputStream:定位并打开资源,返回资源对应的输入流。每次调用都会返回新的输入流,调用者在使用完毕后必须关闭该资源。 

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

Resource接口其他的方法: 
● exists:返回Resource所指向的底层资源是否存在 
● isReadable:返回当前Resource代表的底层资源是否可读 
● isOpen:返回Resource资源文件是否已经打开,如果返回true,则只能被读取一次然后关闭以避免内存泄漏;常见的Resource实现一般返回false 
● getURL:如果当前Resource代表的底层资源能由java.util.URL代表,则返回该URL,否则抛出IO异常 
● getURI:如果当前Resource代表的底层资源能由java.util.URI代表,则返回该URI,否则抛出IO异常 
● getFile:如果当前Resource代表的底层资源能由java.io.File代表,则返回该File,否则抛出IO异常 
● 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.javass.cn将返回“”,因为只返回文件路径。 
● getDescription:返回当前Resource代表的底层资源的描述符,通常就是资源的全路径(实际文件名或实际URL地址)。 

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

Spring提供了很多内置Resource实现:

  • ByteArrayResource
  • InputStreamResource 
  • FileSystemResource 
  • UrlResource 
  • ClassPathResource
  • ServletContextResource
  • VfsResource等 

二. 具体实现

1. UrlResource

        代表URL资源,用于简化URL资源访问,是对java.net.URL的包装。在java中,将不同来源的资源抽象成URL,通过注册不同的handler来处理不同来源的资源的读取逻辑。一般不同类型使用不同的前缀。

        isOpen永远返回false,表示可多次读取资源。 
        UrlResource应该提供标准的协议前缀,一般支持如下资源访问: 

  • http:通过标准的http协议访问web资源,如new UrlResource(“http://地址”); 
  • ftp:通过ftp协议访问资源,如new UrlResource(“ftp://地址”); 
  • file:通过file协议访问本地文件系统资源,如new UrlResource(“file:d:/test.txt”) 
UrlResource ur = new UrlResource("file:web.xml")

        但是UrlResource无法解决相对classpath路径或servletContext的处理方法,因此需要其他的Resource实现类。

2. ClassPathResource

        代表classpath路径的资源,将使用ClassLoader进行加载资源。主要优势是方便访问类加载路径下的资源,尤其是Web应用,因为它可以自动搜索位于WEB-INF/classes下的资源文件

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


ClassPathResource提供了三个构造器: 

  • public ClassPathResource(String path):使用默认的ClassLoader加载“path”类路径资源; 
  • public ClassPathResource(String path, ClassLoader classLoader):使用指定的ClassLoader加载“path”类路径资源; 
  • public ClassPathResource(String path, Class<?> clazz):使用指定的类加载“path”类路径资源,将加载相对于当前类的路径的资源; 
public static void Test_ClassPathResource() throws IOException {
	Resource resource = new ClassPathResource("book.xml");
	
}

    当Spring获取资源时,路径字符串前缀是"classpath:",则系统将会自动创建ClassPathResource对象

3. FileSystemResource

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

public static void Test_FileSystemResource() {
	File file = new File("d:/test.txt");
	Resource resource = new FileSystemResource(file);
	if (resource.exists()) {
		dumpStream(resource);
	}
	Assert.isTrue(!resource.isOpen());
}

    当Spring获取资源时,路径字符串前缀是"file:",则系统将会自动创建FileSystemResource对象


4. ServletContextResource

         访问Web Context下相对路径下的资源,入参的资源位置是相对于Web应用根路径的位置(工程文件夹下,WEB-INF所在的那级文件夹)。用于简化servlet容器的ServletContext接口的getResource操作和getResourceAsStream操作。 

        使用ServletContextResource无需关心资源是否被解压缩出来,或者直接存放在JAR文件中,都可以通过Servlet容器访问。

        入参需要ServletContext和字符串类型

public class ResourceTest {
	ServletContextResource resource = new ServletContextResource(servletContext,"spring.xml");
}

5. InputStreamResource

        代表java.io.InputStream字节流,对于getInputStream操作将直接返回该字节流,因此只能读取一次该字节流,即isOpen永远返回true(其他Resource大都为false可以多次读取) 

        只有当没有合适的Resource实现时,才考虑使用InputStreamResource。一般考虑使用ByteArrayResource

public static void Test_InputStreamResource() {
	ByteArrayInputStream bis = new ByteArrayInputStream(
			"Hello Spring!".getBytes());
	Resource resource = new InputStreamResource(bis);
	if (resource.exists()) {
		dumpStream(resource);
	}
	Assert.isTrue(resource.isOpen());
}

入参需要InputSteam类型

public class ResourceTest {	
	//需要inputStream作为入参
	InputStreamResource resource = new InputStreamResource(inputStream);
}

6. ByteArrayResource

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

        入参需要byte[] 字节数组类型

public static void Test_ByteArrayResource() {
	Resource resource = new ByteArrayResource("Hello!Spring!你好!".getBytes());
	if (resource.exists()) {
		dumpStream(resource);
	}
}
	
private static 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) {  
            }  
        }  
}

        ByteArrayResource因为入参可以是byte[]类型,所以用途比较广泛,可以把从网络或者本地资源都转换为byte[]类型,然后用ByteArrayResource转化为资源。

猜你喜欢

转载自blog.csdn.net/u010086122/article/details/81607127
今日推荐