5.2. Spring访问资源

Resource接口

spring为资源访问提供了一个Resource接口,该接口提供了更强的资源访问能力。

主要方法:

  • getInputStream():定位并打开资源,返回资源对应的输入流。每次调用都返回新的输入流。调用者必须负责关闭输入流。
  • exists():返回Resource所指向的资源是否存在。
  • isOpen():返回资源文件是否打开,如果资源文件不能多次读取,每次读取结束时应该显示关闭,防止资源泄漏。
  • getFile():返回资源对应的File对象。
  • getURL:返回资源对应的URL。

最后两个方法通常无需使用,仅在通过简单方式访问无法实现时,Resource才提供传统的资源访问功能。

Resource接口本身不提供任何底层资源的实现逻辑,针对不同的底层资源,Spring提供不同的Resource实现类。这是典型的策略模式。

Resource实现类

  • UrlResource:访问网络资源的实现类。
  • ClassPathResource:访问类路径资源。
  • FileSystemResource:访问文件系统资源。
  • ServletContextResource:访问相对于ServletContext路径下的资源的实现类。
  • InputStreamResource:访问输入流资源的实现类。
  • ByteArrayResource:访问字节数组资源。

使用ServletContextResource访问应用相关资源

ServletContextResource类访问WebContext下相对路径下的资源。

构造方法:public ServletContextResource(ServletContext servletContext, String path)

使用ServletContextResource访问资源无需关心资源是否被解压缩出来,直接存放在jar中的资源也可以通过servlet容器访问。

访问字节数组资源

InputStreamResource用来访问二进制输入流资源,只有当没有合适的Resource实现时,才考虑使用InputStreamResource,通常优先考虑使用ByteArrayResource,或者基于文件的Resource实现。

InputStreamResource是一个总被打开的Resource,所以isOpen()方法总是返回true。因此需要多次读取某个流,就不要使用它。

个别情况下可以使用InputStreamResource例如从数据库中读取一个Blob对象,程序需要获取该Blob对象内容,就可以先通过Blob的getBinaryStream()方法获取二进制输入流,再将这个流包装成Resource对象,然后就个可以通过Resource对象来访问Blob对象所包含的资源了。

InputStreamResource的效率并不好。

使用前缀方式访问资源


UrlResource res = new UrlResource("file:///d:GenreUserId/1.txt");

UrlResource虽然是为了网络资源设计的,但通过使用file:前缀也可以访问本地磁盘资源。

常用的前缀:
- file:
- http:
- ftp:
- classpath:

需要注意file: 前缀的用法

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

上面两行代码读取了相同的配置资源文件。
问题是:如果程序中明明采用的一个是绝对路径、一个相对路径,为什么执行效果没有任何区别?

产生问题的原因:当 FileSystemXmlApplicationContext 作为 ResourceLoader 使用时,它会发生变化,FileSystemApplicationContext 会简单地让所有绑定的 FileSystemResource 实例把绝对路径都当成相对路径处理,而不管是否以斜杠开头,所以上面两行代码的效果是完全一样的。

如果程序中需要访问绝对路径,则不要直接使用 FileSystemResourceFileSystemXmlApplicationContext 来指定绝对路径。建议强制使用 file: 前缀来区分相对路径和绝对路径,例如如下两行代码:

ApplicationContext ctx = new FileSystemXmlApplicationContext("file:bean.xml"); 
ApplicationContext ctx = new FileSystemXmlApplicationContext("file:/bean.xml");

上面第一条语句访问相对路径下的 bean.xml,第二条语句访问绝对路径下 bean.xml。相对路径以当前工作路径为路径起点,而绝对路径以文件系统根路径为路径起点。

ResourceLoader接口、ResourceLoaderAware接口

  • ResourceLoader:实现类实例可以获得一个Resource实例。
  • ResourceLoaderAware:接口实例获得一个ResourceLoader实例。

ResourceLoader只有一个方法:

Resource getResource(String location)

ApplicationContext的实现类都实现了ResourceLoader接口。
因此ApplicationContext可以直接获得Resource实例, 进而拥有加载资源的能力。

Resource res = ctx.getResource("1.txt");

通过ApplicationContext获取资源的具体实现类由创建ApplicationContext时使用的实现类决定。也可以使用前缀来强制指定使用那种实现类来读取资源。

ApplicationContext中使用资源

ApplicationContext确定资源访问策略有两种方式:
* 使用ApplicationContext实现类指定访问策略。
* 使用前缀指定访问策略。

前缀访问可以使用classpath*:来加载多个XML配置文件。指定的文件也可以使用通配符的形式配置,如 ClassPathXmlApplicationContext("beans*.xml")。通配符也可以和classpath*:一起使用。

ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:spring-*.xml");

注意: classpath*:前缀仅仅对ApplicationContext有效classpath*:不可以用于Resource,使用classpath*:一次性访问多个资源是行不通的。

使用Resource作为属性


public class Student{
    private int age;
    private String name;
    Resource resource;
    //getter and setter ...
}

<bean id="student" class="com.erick.d1.hello.Student" >
    <property name="name" value="cat" />
    <property name="age" value="99" />
    <property name="resource" value="classpath:user.properties" />
bean>

你可能感兴趣的:(Spring学习笔记,spring,springCore)