(2)spring中的resouces(一)

1.介绍

java标准的 java.net.URL类和用于各种前缀标准处理程序并不满足访问底层资源,例如, 没有标准化的URL实现可用于访问需要从类路径获得的或与servlet上下文的资源。虽然可以为专用URL前缀注册新的处理程序(类似于http:),这通常是相当的复杂,ulr的接口缺失一些功能,比如检查所指向资源是否存在的方法

2. Resource的接口

spring的Resource 接口是用来抽象访问底层的资源更加有能力的接口

public interface Resource extends InputStreamSource {

    boolean exists();

    boolean isOpen();

    URL getURL() throws IOException;

    File getFile() throws IOException;

    Resource createRelative(String relativePath) throws IOException;

    String getFilename();

    String getDescription();

}
public interface InputStreamSource {

    InputStream getInputStream() throws IOException;

}

Resource 接口有一些重要的方法:

getInputStream(): 访问和打开资源,返回一个正在读的资源的InputStream 输入流,每次调用期望返回一个新的InputStream流,调用方有责任关闭流

exists(): 返回一个boolean值,指示这个资源是否存在

isOpen(): 返回值为一个布尔值, 该布尔值表示该资源是否是一个打开的流的操作,如果为true,则刘不能被多次读取,并且只能读取一次,然后关闭资源以避免资源泄露,除了InputStreamResource,其他关于resource 的实现都会返回false

getDescription():返回一个关于该resource的描述,用于在使用资源时输出错误,这通常为文件的全限定名或者资源的实际的URL

其他的方法允许你获取实际的URL或者标识资源的文件对象(如果底层实现是兼容,并支持这个功能)

在 spring 里,Resource 抽象有着相当广泛的使用,比如,当需要一个资源时,Resource 可以作为方法签名里的一个参数类型。在 spring api 中,有些方法(如各种 ApplicationContext 实现的构造函数)会直接采用普通格式的String 路径来创建合适的 Resource,调用者也可以通过在路径里带上指定的前缀来创建特定 Resource 实现。

Resource 接口(实现)不仅可以被 spring 大量的应用,其也非常适合作为你编程中访问资源的辅助工具类。当你仅需要使用到 Resource 接口实现时,可以直接忽略 spring 的其余部分。单独使用 Rsourece 实现,会造成代码与 spring 的部分耦合,可也仅耦合了其中一小部分辅助类,而且你可以将 Reource 实现作为 URL 的一种访问底层更为有效的替代,与你引入其他库来达到这种目的是一样的

需要注意的是 Resource 实现并没有去重新发明轮子,而是尽可能地采用封装。举个例子,UrlResource 里就封装了一个 URL 对象在其内的逻辑就是通过封装的 URL 对象来完成的

3. 内置的resources实现

在spring中,提供了一些开箱即用的Resource实现

  • UrlResource

UrlResourcejava.net.URL的封装,被用来访问url可以访问的任意对象,比如file文件,http targe 和 FTP target等,所有的urls有一个标准的字符串表示,比如使用标准化的前缀,可以得到一个url类型,当中就包括用于访问文件系统路劲的file,用户访问HTTP协议的http,通过 ftp 协议访问资源的ftp等等

  • ClassPathResource

可以使用 ClassPathResource 来获取类路径上的资源ClassPathResource 可以使用线程上下文的加载器、调用者提供的加载器或指定的类中的任意一个来加载资源

ClassPathResource 可以从类路径上加载资源,其可以使用线程上下文加载器、指定加载器或指定的 class 类型中的任意一个来加载资源

当类路径上资源存于文件系统中,ClassPathResource 支持以 java.io.File 的形式访问,可当类路径上的资源存于尚未解压(没有 被Servlet 引擎或其他可解压的环境解压)的 jar 包中,ClassPathResource 就不再支持以 java.io.File 的形式访问。鉴于上面所说这个问题,spring 中各式 Resource 实现都支持以 jave.net.URL 的形式访问。

  • FileSystemResource

这是针对 java.io.File 提供的 Resource 实现。显然,我们可以使用 FileSystemResource 的 getFile() 函数获取 File 对象,使用 getURL() 获取 URL 对象。

  • ServletContextResource

这是为了获取web 根路径的 ServletContext 资源而提供的 Resource 实现

ServletContextResource 完全支持以流和 URL 的方式访问,可只有当 web 项目是已解压的(不是以 war 等压缩包形式存在)且该 ServletContext 资源存于文件系统里,ServletContextResource 才支持以 java.io.File 的方式访问。至于说到,我们的 web 项目是否已解压和相关的 ServletContext 资源是否会存于文件系统里,这个取决于我们所使用的 Servlet 容器。若 Servlet 容器没有解压 web 项目,我们可以直接以 JAR 的形式的访问,或者其他可以想到的方式(如访问数据库)等。

  • InputStreamResource

这是针对 InputStream 提供的 Resource 实现。建议,在确实没有找到其他合适的 Resource 实现时,才使用 InputSteamResource。如果可以,尽量选择 ByteArrayResource 或其他基于文件的 Resource 实现来代替

与其他 Resource 实现已比较,InputStreamRsource 倒像一个已打开资源的描述符,因此,调用 isOpen() 方法会返回 true。除了在需要获取资源的描述符或需要从输入流多次读取时,都不要使用 InputStreamResource 来读取资源。

  • ByteArrayResource

这是针对字节数组提供的 Resource 实现。可以通过一个字节数组来创建 ByteArrayResource

当需要从字节数组加载内容时,ByteArrayResource 是一个不错的选择,使用 ByteArrayResource 可以不用求助于 InputStreamResource。

4.ResourceLoader 接口

ResourceLoader 接口是用来加载 Resource 对象的,换句话说,就是当一个对象需要获取 Resource 实例时,可以选择实现 ResourceLoader 接口。

public interface ResourceLoader {

    Resource getResource(String location);

}

spring 里所有的应用上下文都是实现了 ResourceLoader 接口,因此,所有应用上下文都可以通过 getResource() 方法获取 Resource 实例。

当你在指定应用上下文调用 getResource() 方法时,而指定的位置路径又没有包含特定的前缀,spring 会根据当前应用上下文来决定返回哪一种类型 Resource。举个例子,假设下面的代码片段是通过 ClassPathXmlApplicationContext 实例来调用的

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");

那 spring 会返回一个 ClassPathResource 对象;类似的,如果是通过实例 FileSystemXmlApplicationContext 实例调用的,返回的是一个 FileSystemResource 对象;如果是通过 WebApplicationContext 实例的,返回的是一个 ServletContextResource 对象…… 如上所说,你就可以在指定的应用上下中使用 Resource 实例来加载当前应用上下文的资源。

还有另外一种场景里,如在其他应用上下文里,你可能会强制需要获取一个 ClassPathResource 对象,这个时候,你可以通过加上指定的前缀来实现这一需求,如:

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");

类似的,你可以通过其他任意的 url 前缀来强制获取 UrlResource 对象:

Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt")

给出一个表格来总结一下 spring 根据各种位置路径加载资源的策略:

refix Example Explanation
classpath: classpath:com/myapp/config.xml Loaded from the classpath.
file: [file:///data/config.xml](file:///data/config.xml) Loaded as a URL, from the filesystem.
http: [http://myserver/logo.png](http://myserver/logo.png) Loaded as a URL.
(none) /data/config.xml Depends on the underlying ApplicationContext.

不管是ClassPathXmlApplicationContext,还是FileSystemXmlApplicationContext,还是XmlWebApplicationContext,从继承关系可以看出,这些类最终继承了DefaultResourceLoader的这个类,这些类调用getResource方法的方法,实际上调用的是DefaultResourceLoader.getResource的方法,getResource

你可能感兴趣的:((2)spring中的resouces(一))