spring——(5)Resource

来源:互联网 发布:卓行信贷网络借贷 编辑:程序博客网 时间:2024/05/20 10:21

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

Resource接口

Spring的Resource接口代表底层外部资源,提供了对底层外部资源的一致性访问接口。
接口中的方法如下:
这里写图片描述

  • 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.javass.cn将返回“”,因为只返回文件路径。
  • getDescription:返回当前Resource代表的底层资源的描述符,通常就是资源的全路径(实际文件名或实际URL地址)。

Resource接口提供了足够的抽象,足够满足我们日常使用。而且提供了很多内置Resource实现:ByteArrayResource、InputStreamResource 、FileSystemResource 、UrlResource 、ClassPathResource、ServletContextResource、VfsResource等。

ResourceLoader 接口

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

public interface ResourceLoader {    Resource getResource(String location);}

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

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

Resource template = ctx.getResource("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 根据各种位置路径加载资源的策略:

前缀 样例 说明 classpath: classpath:com/myapp/config.xml 从类路径加载 file: file:///data/config.xml 将其作为 URL 对象,从文件系统加载 http: http://myserver/logo.png 将其作为 URL 对象 加载 (none) /data/config.xml 取决于底层的 ApplicationContext

举个例子:

public class TestResource implements ApplicationContextAware  {    private ApplicationContext applicationContext;    public void setApplicationContext(ApplicationContext applicationContext)            throws BeansException {        this.applicationContext = applicationContext;    }    public void resource() throws IOException {        Resource resource = applicationContext.getResource("classpath:test.txt");//      ClassPathResource resource = (ClassPathResource) applicationContext.getResource("classpath:test.txt");        System.out.println(resource.getFilename());        System.out.println(resource.contentLength());    }}

这个类实现了ApplicationContextAware 接口,这样就可以获取ApplicationContext 对象,用ApplicationContext 对象获取Resource 。
在类中定义一个resource()方法,在这个方法中获取一个text.txt文件(位置在src/main/resources下)并返回一个Resource对象,这里我是用的是classpath,所以返回的是ClassPathResource对象,只是这里我直接使用Resource接收。
现在在bean中配置一下:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd"        default-autowire="byName">    <bean id="testResource" class="com.mss.test.TestResource"></bean></beans>

写一个测试类:

@RunWith(BlockJUnit4ClassRunner.class)public class TestOneInterface extends UnitTestBase{    public TestOneInterface() {        super("classpath*:spring-ioc.xml");    }    @Test    public void testAutoWriter() {        TestResource testResource=super.getBean("testResource");        try {            testResource.resource();        } catch (IOException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

运行结果:

test.txt0

由于是一个空的文件,所以长度是0;

上面的classpath是什么意思?
看一个图片
这里写图片描述
这个路径就是classpath

我们也可以用file:

public class TestResource implements ApplicationContextAware  {    private ApplicationContext applicationContext;    public void setApplicationContext(ApplicationContext applicationContext)            throws BeansException {        this.applicationContext = applicationContext;    }    public void resource() throws IOException {        Resource resource = applicationContext.getResource("file:D:\\eclipse\\eclipse-workspace\\HelloSpring\\src\\main\\resources\\test.txt");        System.out.println(resource.getFilename());        System.out.println(resource.contentLength());    }}

运行结果是一样的。

在看一下使用http:

public class TestResource implements ApplicationContextAware  {    private ApplicationContext applicationContext;    public void setApplicationContext(ApplicationContext applicationContext)            throws BeansException {        this.applicationContext = applicationContext;    }    public void resource() throws IOException {        Resource resource = applicationContext.getResource("https://www.duba.com/?f=liebao");        System.out.println(resource.getFilename());        System.out.println(resource.contentLength());    }}

这里使用的是毒霸网址导航的链接,看一下运行结果:

?f=liebao256405

如果前缀是空会怎么样?
前面已经说到当你在指定应用上下文调用 getResource() 方法时,而指定的位置路径又没有包含特定的前缀,spring 会根据当前应用上下文来决定返回哪一种类型 Resource。 看一下代码:

public class TestResource implements ApplicationContextAware  {    private ApplicationContext applicationContext;    public void setApplicationContext(ApplicationContext applicationContext)            throws BeansException {        this.applicationContext = applicationContext;    }    public void resource() throws IOException {        Resource resource = applicationContext.getResource("test.txt");        System.out.println(resource.getFilename());        System.out.println(resource.contentLength());    }}

还记得我们的测试基类吗?

public class UnitTestBase {    private ClassPathXmlApplicationContext context;    private String springXmlpath;    public UnitTestBase() {}    public UnitTestBase(String springXmlpath) {        this.springXmlpath = springXmlpath;    }    @Before    public void before() {        if (StringUtils.isEmpty(springXmlpath)) {            springXmlpath = "classpath*:spring-*.xml";        }        try {            context = new ClassPathXmlApplicationContext(springXmlpath.split("[,\\s]+"));            context.start();        } catch (BeansException e) {            e.printStackTrace();        }    }    .......................}

我们这里初始化ioc容器时,使用的是ClassPathXmlApplicationContext,所以Spring会把当前没有前缀的Resource 作为classpath前缀处理。

原创粉丝点击