Spring Framework 官方文档学习(三)之Resource

时间:2022-05-10 20:39:19

起因

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

所以,Spring提供了 Resource 接口。

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

例如,UrlResource 就封装了一个URL。

介绍

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");

ps:

做了一个小demo放在码云,有兴趣的可以down下来看看。

我是地址