起因

标准JDK中使用 java.net.URL 来处理资源,但有很多不足,例如不能限定classpath,不能限定 ServletContext 路径。

所以,Spring提供了 Resource接口。

注意,Spring提供的Resource抽象不是要取代(replace)标准JDK中的功能,而是尽可能的封装(wrap)它。

例如,UrlResource

介绍

Spring内置了很多Resource实现,以用于不同情况。如下:

UrlResource ,ClassPathResource ,FileSystemResource ,ServletContextResource ,InputStreamResource ,ByteArrayResource 

基本上可以根据名字判断出各自的适用环境。

使用

ResourceLoader,这个接口只有一个方法,用于返回Resource实例。

ApplicationContext接口继承了该接口,就是说,所有的ApplicationContext实现都实现了其方法,能够返回一个Resource实例。

默认情况下,根据不同的ApplicationContext实现,会返回不同的Resource类型,例如:



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



1 如果ctx是一个ClassPathXmlApplicationContext,那会返回一个ClassPathResource。
2 如果ctx是一个FileSystemXmlApplicationContext ,那会返回一个FileSystemResource。
3 如果ctx是一个WebApplicationContext,那会返回一个ServletContextResource。



但是,可以通过前缀来指定返回的Resource 实例类型:



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



前缀列表:

Prefix

Example

Explanation

classpath:

classpath:config/app.xml

从classpath中加载。

file:

file:///data/app.xml

FileSystem的URL。

http:

http://myserver/logo.png

URL。

(none)

/data/app.xml

依赖具体的ApplicationContext实现。

另外,ClassPathXmlApplicationContext可以根据 Class的路径 推断出资源路径。需要在同一个包下。 



new ClassPathXmlApplicationContext(new String[]{"a.xml","b.xml"}, Config.class);



上面这个例子,要求a.xml、b.xml、Config.class在同一个包下。



 



通过指定 configLocation 来创建ApplicationContext实例时,这个 configLocation 可以含有 通配符(wild character),而且可以和 ant-style patterns结合。



但是需要注意一点,当ant-style pattern 与 classpath前缀 结合时,可能会不完全搜索,从而导致问题。这时需要使用 classpath*前缀。



使用 classpath* 前缀总是没错的。



 



关于FileSystemResource



由于历史原因,不同ApplicationContext实例返回的FileSystemResource会有不同。



具体分为两类情况:



1、由 FileSystemApplicationContext 实例返回。这种情况下,会简单粗暴的强制所有FileSystemResource实例 将路径视为相对路径,无论是否以斜线【 /】开头。



就是说下面这两个是等效的:



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



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



另外,上面这两个又分别等效于下面这两个:



FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("some/resource/path/myTemplate.txt");



FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("/some/resource/path/myTemplate.txt");



 

2、由其他ApplicationContext实例返回。这种情况下,FileSystemResource会按我们预期的来处理相对路径和绝对路径:相对路径是相对于当前工作路径;绝对路径是FileSystem的根路径。



 



针对第一种情况,如果真想使用FileSystem的绝对路径,最好不要使用 FileSystemResource /FileSystemXmlApplicationContext,使用URL前缀 file:来返回UrlResource即可。如下:



// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt");



// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
ApplicationContext ctx = new FileSystemXmlApplicationContext("file:///conf/context.xml");