【转】https://blog.csdn.net/hbtj_1216/article/details/85487787
参考:官方文档
1 简介
Java
标准库中的java.net.URL
类和标准处理器对于处理低层的资源没有提供很好的功能。例如,并没有提供一个URL
的实现能够从classpath
或者ServletContext
中读取资源等等。因此,在Spring
中提供了这样一个Resource
接口,能够更加方便的读取各种资源。
2 Resource接口
Spring
提供的Resource
接口,是对第低层资源访问进行的一个抽象,提供能方便的使用。
下面是org.springframework.core.io.Resource
接口的定义:
public interface Resource extends InputStreamSource { /** * 判断资源在物理上是否存在 */ boolean exists(); /** * 表明该资源中的非空内容是否可以通过getInputStream()读取 */ default boolean isReadable() { return exists(); } /** * 表明该资源是否被一个打开的stream处理 */ default boolean isOpen() { return false; } /** * 判断该资源是否代表文件系统中的一个文件 */ default boolean isFile() { return false; } /** * 返回该资源的URL */ URL getURL() throws IOException; /** * 返回该资源的URI */ URI getURI() throws IOException; /** * 返回该资源对应的File */ File getFile() throws IOException; /** * 返回一个ReadableByteChannel(可读的字节流通道) */ default ReadableByteChannel readableChannel() throws IOException { return Channels.newChannel(getInputStream()); } /** * 返回资源中内容的长度 */ long contentLength() throws IOException; /** * 返回该资源的最后修改时间 */ long lastModified() throws IOException; /** * 创建一个和该资源相关的资源 */ Resource createRelative(String relativePath) throws IOException; /** * 返回文件名 */ @Nullable String getFilename(); /** * 返回资源的描述 */ String getDescription(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
Resource
接口继承的InputStreamSource
接口中海油一个非常重要的方法:
public interface InputStreamSource {/** * 找到并打开资源,返回读取资源内容的InputStream. 每次调用返回一个新的InputStream. */ InputStream getInputStream() throws IOException; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3 Spring中内置的Resource接口的实现类
Spring
中包含了如下几个Resource
接口的实现类:
- UrlResource:从
URL
获取资源。 - ClassPathResource:从
classpath
获取资源。 - FileSystemResource:从文件系统获取资源。
- ServletContextResource:从
servlet
上下文获取资源。 - InputStreamResource:从
InputStream
获取资源。 - ByteArrayResource:从字节数组获取资源。
UrlResource
UrlResource
是对java.net.URL
的封装,可以被用来访问任何可以通过URL
访问的资源对象,例如文件、HTTP
目标对象、FTP
目标对象等等。
每种类型的URL
都有表示该类型资源的前缀。例如file:
表示访问文件系统的URL
;http:
表示通过http
协议访问;ftp:
表示通过ftp
协议访问。
ClassPathResource
ClassPathResource
表示从classpath
中获取资源。
FileSystemResource
FileSystemResource
是对java.io.File
和java.nio.file.Path
的封装,代表从文件系统中读取文件。
ServletContextResource
ServletContextResource
是为了方便你从ServletContext
中获取资源而设计的,可以从相对于web
应用程序的根目录中获取资源。
InputStreamResource
InputStreamResource
是用来从给定的InputStream
中获取资源的。
ByteArrayResource
ByteArrayResource
用来从给定的字节数组中获取资源,它会创建一个ByteArrayInputStream
。
4 ResourceLoader
ResourceLoader
接口是用来加载资源的,它提供了一个getResource
函数用来返回一个Resource
对象。下面是它的定义:
public interface ResourceLoader {String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; Resource getResource(String location); @Nullable ClassLoader getClassLoader(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
所有的应用程序上下文都实现了ResourceLoader
接口,因此可以从应用程序上下文中获取Resource
对象:
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
- 1
如果在调用getResource()
的时候,指定的资源路径上没有给出前缀,那么Spring
会根据context
的类型返回一个合适类型的资源对象。例如,在ClassPathXmlApplicationContext
对象上调用getResource()
函数,则会返回一个ClassPathResource
对象。
如果你指定了前缀,那么不管context
是什么类型,都将返回前缀对应的资源类型,例如:
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
- 1
下表总结了资源路径对应的资源类型:
前缀 | 例子 | 说明 |
---|---|---|
classpath: | classpath:com/myapp/config.xml | 从classpath 加载资源。 |
file: | file:///data/config.xml | 从文件系统加载资源。 |
http: | http://myserver/logo.png | 使用http 协议加载资源。 |
(none) | /data/config.xml | 根据context 类型判断。 |
5 ResourceLoaderAware接口
ResourceLoaderAware
是Spring
提供的一个回调接口,用于注入ResourceLoader
:
public interface ResourceLoaderAware extends Aware { void setResourceLoader(ResourceLoader resourceLoader); }
- 1
- 2
- 3
- 4
如果一个类实现了ResourceLoaderAware
接口并在Spring
上下文中注册为一个bean
,那么context
会调用它的setResourceLoader()
方法将context
本身设置进去(因为所有的context
都实现了ResourceLoader
接口)。
下面是一个例子:
@Component
public class ResourceBean implements ResourceLoaderAware { private ResourceLoader resourceLoader; @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } public ResourceLoader getResourceLoader() { return resourceLoader; } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
@Test
public void test() { ApplicationContext ctx = new ClassPathXmlApplicationContext("test/resourceLoaderAware.xml"); ResourceBean resourceBean = ctx.getBean(ResourceBean.class); ResourceLoader loader = resourceBean.getResourceLoader(); Assert.assertTrue(loader instanceof ApplicationContext); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
上述方法采用实现
ResourceLoaderAware
接口的方式注入ResourceLoader
,属于侵入式的方法。从Spring 2.5
之后,可以直接通过@Autowired
自动注入的方式注入ResourceLoader
。
6 应用个上下文和资源路径
6.1 构造一个应用上下文
应用上下文的构造函数通常将资源的路径以一个字符串或者字符串数组传入。当路径没有前缀的时候,资源的类型依据上下文的类型构建。
下面的例子,通过资源的路径构造一个ClassPathXmlApplicationContext
上下文对象:
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
- 1
下面的例子,根据资源路径构造一个FileSystemXmlApplicationContext
上下文对象:
ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/appContext.xml");
- 1
也可以通过路径前缀指定具体资源的类型。
6.2 资源路径支持通配符
可以通过*
来表示一批资源文件:
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
- 1
- 2
- 3
- 4
6.3 classpath*:和classpath:
classpath*:
和classpath:
的主要区别体现在:
classpath:
:只会在当前项目的WEB-INF/classes
路径下查找文件。classpath*:
:不只在当前羡慕的WEB-INF/classes
路径下查找文件,还会到第三方jar
文件的WEB-INF/classes
查找文件。
6.4 FileSystemResource的路径问题
为了兼容,FileSystemXmlApplicationContext
中的相对路径和绝对路径都将视为相对路径,相对于当前项目的工作目录。
下面两个是等价的:
ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/context.xml");
- 1
ApplicationContext ctx = new FileSystemXmlApplicationContext("/conf/context.xml");
- 1
如果真的需要绝对路径,应该尽量使用UrlResource
并通过file:
前缀来指定:
// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt");
- 1
- 2
// force this FileSystemXmlApplicationContext to load its definition via a UrlResource
ApplicationContext ctx = new FileSystemXmlApplicationContext("file:///conf/context.xml");