Spring基础十二:Resource

JDK自带的java.nt.URL类可以通过路径来访问各类资源,不同的url前缀指向不同类型的资源,比如文件系统或web资源。不过这个类的功能有所不足,缺少访问classPath或ServletContext下资源的能力,并且缺少一些常用的方法。

因此,Spring定义了一套加载底层资源的机制,用来取代java.net.URL,该机制的核心是两个接口:ResourceLoader和Resource。

Resource接口

Resource接口,替代java.nt.URL,用以指向某个资源,该接口的定义如下:

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

它继承自InputStreamSource:

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

其中几个重要方法的含义如下表:

方法解释
getInputStream()打开资源返回一个InputStream,每次调用都会创建一个新的InputStream,调用者负责关闭
exists()资源是否存在
isOpen()资源是否打开,仅InputStreamResource可能返回true,其他必然是false
getDescription()资源的描述,一般是文件全路径名或资源的完整URL
getURL()返回资源URL,前提是该资源位置能够用URL表示
getFile()返回资源指向的文件,前提是该资源确实指向一个文件

Spring框架接口广泛使用Resource,或资源路径作为参数;用户代码也可以直接创建Resouce实例来访问资源,比使用java.net.URL更加方便(如果不介意代码与Spring耦合的话)。

内置Resource实现

Spring提供了几种类型的Resource实现:

  • UrlResource
  • ClassPathResource
  • FileSystemResource
  • ServletContextResource
  • InputStreamResource
  • ByteArrayResource

我们可以通过构造函数直接创建上述类型的Resouce,更多的情况下,Spring的接口接受一个字符串类型的资源路径,内部通过PropertyEditor决定创建那种类型的Resource。

UrlResource

UrlResource包装一个java.net.URL,用于访问可以通过url定位的资源,比如文件,http资源,ftp资源等。所有的URL都能用字符串来表示,通过标准的前缀来区分URL类型,比如file:访问文件系统路径,http:用http协议访问web资源,ftp:用ftp协议访问远程文件。

ClassPathResource

ClassPathResource从类路径加载资源,它使用当前线程的class loader,或给定的classLoader来加载资源。如果资源是本地类路径下的文件,那么getFile方法能返回一个文件对象;资源也有可能在jar包里面,无论何种情况,getURL都能返回一个有效的url。

前面讲过,Spring接口往往接受一个字符串类型的资源路径,前缀为classpath:的路径指向ClassPathResource。

FileSystemResource

包装java.io.Filejava.nio.file.Path的资源类型。

ServletContextResource

访问Servlet上下文资源,比如相对于web根目录下的资源。具体的情况,与web容器有关。

InputStreamResource

包装一个已经打开的Inputstream,此类型的资源不能读取多次,也不能保存起来备用。实际上只有InputStreamResource的isOpen方法放回true。由于这些限制,仅仅在其他类型的Resource不适用的时候,才使用该类型。

ByteArrayResource

包装一个byte数组。

ResourceLoader

ResoourceLoader定义了从资源位置加载Resource的接口:

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

所有的ApplicationContext都实现了ResoourceLoader,因此我们可以这样使用:

//从类路径加载资源
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");

//从网络加载web资源
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");

//从哪里加载资源?
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");

前两行代码通过路径前缀,明确告知ResoourceLoader加载何种类型的资源,而第三句没有明确指明。Context如何解释这种不带前缀的路径,取决于具体的Context实现;如果是ClassPathXmlApplicationContext,则解释为类路径,如果是FileSystemXmlApplicationContext,则为文件系统路径。

ResourceLoaderAware

用户bean通过实现ResourceLoaderAware接口,可以得到ResourceLoader的引用。

public interface ResourceLoaderAware {
    void setResourceLoader(ResourceLoader resourceLoader);
}

当然,现在通过@Autowire也可以直接注入ResourceLoader依赖到属性或构造参数。

实际上,这里得到的就是ApplicationContext本身,因此注入ApplicationContext的引用也是OK的,不过从设计原则出发,依赖更小的接口ResourceLoader更佳。

注入Resource属性

拿到ResourceLoader引用,bean可以动态地加载资源,但是如果bean仅依赖静态资源,那么可以直接声明一个Resource
属性,然后通过属性值注入进去。

比如下面的myBean有一个Resource类型的属性template,bean定义注入了一个字符串值,Spring内部的PropertyEditor会完成类型转换:将字符串解释为资源路径,并通过Context加载Resource。

<bean id="myBean" class="...">
    <property name="template" value="some/resource/path/myTemplate.txt"/>
</bean>

ApplicationContext与资源路径

这部分介绍ApplicationContext的具体类型如何使用资源路径,以及路径通配符的细节。

构建ApplicationContext

很多情况下,Context的自身就需要从xml文件来初始化,不同的Context类型对路径有不同的解释,规则在前面已经介绍过:

//从类路径加载
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");

//从文件路径加载
ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/appContext.xml");

//从类路径加载
ApplicationContext ctx = new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");

ClassPathXmlApplicationContext还提供了一种便捷的方式,仅需要提供xml文件名,通过一个Class对象来指明包路径:

ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"}, MessengerService.class);

通配符

ApplicationContext构造器可以接受多个资源路径,除了一一指定之外,还支持通配符路径。 这里支持两种类型通配符:Ant-style Pattern和 classpath*

Ant-style路径请查阅相关文档,classpath*的意思是从所有匹配的类路径加载资源,而不仅仅是第一个匹配的路径。比如classpath*:conf/appContext.xml匹配所有conf包下面的appContext.xml;还可以将两者结合起来,classpath:com/mycompany/**/service-context.xml匹配以com.mycompany打头的包下面的service-context.xml。

不过在使用Ant-style路径来访问jar包里面的资源,可能会有兼容性问题。因为Spring是通过ClassLoader.getResources()来扫描包路径的,这对文件系统下的类路径肯定有效,但不保证对jar包同样有效;尤其当你的代码工作在某个容器中,使用了容器提供的ClassLoader。

FileSystemResource警示

当FileSystemResoure从FileSystemApplicationContext加载的时候,无论传入的路径是否’/'开头,都会被当做相对(当前工作目录)路径。因此new FileSystemXmlApplicationContext("conf/context.xml")new FileSystemXmlApplicationContext("/conf/context.xml")的效果是一样的。

而其他类型的ApplicationContext加载FileSystemResoure则,将以/开头的路径当做绝对路径,否则当做相对路径。

因此如果实际项目中,想使用绝对文件路径,请使用file:前缀,避开这种微妙的区别,ctx.getResource("file:///conf/context.xml")

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值