spring为资源访问提供了一个Resource接口,该接口提供了更强的资源访问能力,spring框架本身大量使用了Resource来访问底层资源。
Resource接口主要提供了如下几个方法:

  • getInputStream():定位并打开资源,返回资源对应的输入流。
  • exists():返回Resorce所指向的资源是否存在。
  • isOpen():返回资源文件是否打开,如果资源文件不能多次读取,每次读取结束时应该显示关闭,以防止资源泄露。
  • getDescription():返回资源的描述信息,用于资源处理出错时输出该信息,通常是全限定文件名或实际URL。
  • getFile:返回资源对应的File对象。
  • getURL:返回资源对应的URL对象。
1.Resource实现类

(1) 访问网络资源
访问网络资源通过UrlResource类实现,是java.net.URL类型的包装,主要用于访问之前通过URL类访问的资源对象。URL资源通常应该提供标准的协议前缀。file:用于访问文件系统;http:用于通过HTTP协议访问资源;ftp:用于通过FTP协议访问资源。

(2)访问类加载路径下的资源
ClassPathResource用来访问类加载路径下的资源,可自动搜索位于WEB-INF/classes下的资源文件,无须使用绝对路径访问。当执行spring的某个方法时,该方法接受了一个代表资源路径的字符串参数,当spring识别该字符串参数中包含classpath:前缀后,系统将会自动创建ClassPathResource对象。

(3)访问文件系统资源
FileSystemResource类用于访问文件系统资源。当执行spring的某个方法时,该方法接受了一个代表资源路径的字符串参数,当spring识别该字符串参数中包含path:前缀后,系统将会自动创建ClassPathResource对象。

(4)访问应用相关资源
spring提供了ServletContextResource类来访问Web Context下相对路径下的资源。
当程序试图直接通过File来访问Web Context下相对路径下的资源时,应该先使用ServletContext的getRealPath()方法来取得资源绝对路径,再以该绝对路径来创建File对象。
在默认情况下,JSP不能直接访问WEB-INF路径下的任何资源,所以该应用中的JSP页面需要使用ServletContextResource来访问该资源。

(5)访问字节数组资源
spring提供给了InputStreamResource来访问二进制输入流资源。通常情况下,优先考虑使用ByteArrayResource或者基于文件的Resource实现。
spring提供ByteArrayResource用于直接访问字节数组资源,字节数组是一种常见的信息传输方式:网络Socket之间的信息交换,或者线程之间的信息交换等,字节数组都被作为信息载体。ByteArrayResource可将字节数组包装成Resource使用。

2.ResourceLoader接口和ResourceLoaderAware接口
  • ResourceLoader:该接口实现类的实例可以获得一个Resource实例。
  • ResourceLoaderAware:该接口实现类的实例将获得一个ResouceLoader的引用。
    在ResourceLoader接口里有如下方法:
    Resource getResource(String location):该接口仅包含这个方法,该方法用于返回一个Resource实例。ApplicationContext的实现类都实现ResourceLoader接口,因此ApplicationContext可用于直接获取Resource接口。

策略模式:当spring应用需要进行资源访问时,实际上并不需要直接使用Resource实现类,而是调用ResourceLoader实例的getResource()方法来获得资源。ResourceLoader将会负责选择Resource的实现类,也就是确定具体的资源访问策略,从而将应用程序和具体的资源访问策略分离开来。

ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
    Resource res = ctx.getResource("books.xml");
Resource r = ctx.getResource("file:beans.xml");

常见的前缀及对应的访问策略:

  • classpath:以ClassPathResource实例访问类加载路径下的资源。
  • file:以UrlResource实例访问本地文件系统的资源。
  • http:以UrlResource实例访问基于HTTP协议的网络资源。
  • 无前缀:由ApplicationContext的实现类来决定访问策略。
3.使用Resource作为属性

当应用程序中的Bean实例需要访问资源时,spring有更好的解决方法:直接利用依赖注入。

public class TestBean{
        private Resource res;
        setter方法
    }

    <beans>
        <bean id="test" class="..TestBean" p:res="classpath:book.xml"/>
    </beans>

采用依赖注入,允许动态配置资源文件位置,无须将资源文件位置写在代码中,当资源文件位置发生变化时,无须改写程序,直接修改配置文件即可。

4.在ApplicationContext中使用资源

(1)使用ApplicationContext实现类指定访问策略
ClassPathXmlApplicationContext:对应使用ClassPathResource进行资源访问。
FileSystemXmlApplicationContext:对应使用FileSystemResource进行资源访问。
XmlWebApplicationContext:对应使用ServletContextResource进行资源访问。

(2)使用前缀指定访问策略

ApplicationContext ctx = new FileSystemXmlApplicationContext("classpath:beans.xml");

(3)classpath*:前缀的用法
classpath*:前缀提供了加载多个XML配置文件的能力,当使用classpath*:前缀来指定XML配置文件时,系统将搜索类加载路径,找出所有与文件名匹配的文件,分别加载文件中的配置定义,最后合并成一个ApplicationContext。spring将会搜索类加载路径下所有满足该规则的配置文件。
当使用classpath:前缀时,系统通过类加载路径搜索文件,如果找到文件名匹配的文件,系统立即停止搜索,加载该文件,即使有多个文件名匹配的文件,系统也只加载第一个文件。资源文件的搜索顺序取决于类加载路径的顺序,排在前面的配置文件将优先被加载。
classpath*:前缀仅对ApplicationContext有效。
还有一种可以一次性加载多个配置文件的方式,即:指定配置文件时使用通配符。

ApplicationContext ctx = new ClassPathXmlApplicationContext("beans*.xml");

(4)file:前缀的用法

ApplicationContext ctx = new FileSystemXmlApplicationContext("beans.xml");
    ApplicationContext ctx = new FileSystemXmlAppliaction("/beans.xml");

当FileSystemXmlApplicationContext作为ResourceLoader使用时,它会发生变化,FileSystemApplicationContext会简单地让所有绑定的FileSystemResource实例把绝对路径都当成相对路径处理,而不管是否以斜杠开头,所以上面两条代码的效果是一样的。
建议强制使用file:前缀来区分相对路径和绝对路径。
相对路径以当前工作路径为路径起点,而绝对路径以文件系统根路径为路径起点。