资源访问

ClassPathXmlApplicationContext是Spring应用上下文的其中一种实现,它的实例通常可以这样创建:

1 var context = new ClassPathXmlApplicationContext("resources\\app-config.xml"))

可以看到ClassPathXmlApplicationContext拿到文件路径 resources\app-config.xml 之后即能给基于类路径加载配置文件完成Bean的创建,事情出奇地简单!可在简单的背后,却深藏着Spring应用上下文不为人知的努力。资源访问就是其中一件。

众所周知,Spring应用上下文是基于ApplicationContext接口进行实现的。而ApplicationContext接口又继承了ResourceLoader接口,能够加载诸如XML配置文件之类的资源。自然而然的,实现了ApplicationContext接口的Spring应用上下文也就具有加载XML配置文件这种资源的能力。ResourceLoader接口定义如下:

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

该接口只定义了 Resource getResource(String location) 方法,接受一个字符串类型的资源路径之后即能创建一个Resource类型的对象返回给调用者。而Resource是Spring定义的一个关于资源的接口,具有以下几种常见的资源访问方法:
1. InputStream getInputStream() :打开资源之后创建和返回java.io.InputStream类型的对象,以供调用者以数据流的方式读取资源。注意:每次调用该方法都会创建和返回一个新的InputStream类型的对象。用完之后记得把它关掉,以免造成内存泄漏。
2. File getFile() :获取java.io.File类型的对象,能够提供诸如文件位置,文件大小,文件读写权限之类的信息。
3. String getFilename() :获取资源的文件名。
4. String getDescription() :获取资源的描述信息,通常含有资源的完整路径。
5. boolean exists() :检查资源是否存在。

Resource接口具有多种实现,常见的有以下几种:
1.UrlResource:这种实现只是简单封装一下Java基础类库里的java.net.URL。因此,URL能做的事,UrlResource同样也能。
2.ClassPathResource:基于类路径加载资源。
3.FileSystemResource:基于应用程序当前工作目录加载资源。
4.ServletContextResource:基于Web应用程序根目录加载资源。非常明显,这种实现是与Web应用程序挂钩的。

可以看到常见的Resource实现共有四种。不同的Spring应用上下文实现ResourceLoader接口时,创建的资源类型是不同的。对应如下:
1.ClassPathXmlApplicationContext创建的是ClassPathResource类型的资源。
2.FileSystemXmlApplicationContext创建的是FileSystemResource类型的资源。
3.XmlWebApplicationContext创建的是ServletContextResource类型的资源。

于是我们知道了,Spring应用上下文加载XML配置文件的过程是这样的:Spring应用上下文完成实例的创建之后,将会调用ResourceLoader接口创建Resource类型的对象进行XML配置文件的加载。如果Spring应用上下文是ClassPathXmlApplicationContext类型的,创建的则是ClassPathResource类型的资源,能够基于类路径加载XML配置文件;如果Spring应用上下文是FileSystemXmlApplicationContext类型的,创建的则是FileSystemResource类型的资源,能够基于应用程序当前工作目录加载XML配置文件;如果Spring应用上下文是XmlWebApplicationContext类型的,创建的则是ServletContextResource类型的资源,能够基于Web应用程序根目录加载XML配置文件。

额外让人惊喜的是,我们还能这样指定文件路径进行Spring应用上下文的创建:

1 var context = new ClassPathXmlApplicationContext(
2         "file:out\\production\\music-player\\resources\\app-config.xml")

可以看到,我们传给Spring应用上下文的文件路径不但变了,而且新带了个神秘的 file: 前缀。

这是怎么回事呢?

原来,ResourceLoader创建资源时,会先看看文件路径是否带有前缀。如果没带前缀,就会创建前文提到的与Spring应用上下文对应的资源;如果有带前缀,就会根据不同的前缀创建不同的资源。这意味着我们可以通过前缀改变资源的类型,从而改变Spring应用上下文加载XML配置文件的方式。

目前支持的前缀有 classpath:  file:  http:  ftp: 。如果指定 classpath: 前缀,则会创建ClassPathResource,基于类路径加载资源。如果指定 file:  http:  ftp: 前缀,则会创建UrlResource,以java.net.URL的方式加载资源。这意味着如果指定 file: 前缀,则可在前缀后面指定资源的相对路径或绝对路径进行资源的加载;如果指定 http:  ftp: 前缀,则可在前缀后面指定网络资源的位置进行网络资源的加载。

可以看到前缀的引入让资源的加载变得非常灵活,我们随时都能通过添加前缀改变资源的加载方式。那么,Spring应用上下文是否也支持以通配符的方式进行XML配置文件的加载,让事情变得更加方便呢?

答案是肯定的,Spring应用上下文支持Ant风格的通配符。实际上,Spring应用上下文调用ResourceLoader加载资源之前,会先解析通配符找出所有匹配的文件路径。之后,Spring应用上下文以匹配的文件路径为参数循环调用ResourceLoader完成资源的加载。以下是Spring应用上下文支持的Ant风格的通配符:

通配符

用途

示例

?

匹配任意一个字符

通配符路径resources\app-confi?.xml能够匹配这些路径:
1.resources\app-confia.xml
2.resources\app-confib.xml
3.resources\app-confic.xml

*

匹配零或多个字符

通配符路径resources\*.xml能够匹配这些路径:
1.resources\a.xml
2.resources\b.xml
3.resources\c.xml

**

匹配零或多个目录

通配符路径resources\**\app-config.xml能够匹配这些路径:
1.resources\app-config.xml
2.resources\aa\app-config.xml
3.resources\bb\app-config.xml

至此,关于Spring应用上下文是怎样加载XML配置文件的,我们已经弄清楚了。问题在于,XML配置文件是资源,PNG格式的图片是资源,Word文档同样也是资源。如果我们想访问的是诸如PNG格式的图片之类的资源,又该怎么做呢?

总体而言,访问这样的资源有两种方式:一种是自己手动创建资源对象(比如UrlResource,ClassPathResource,FileSystemResource,ServletContextResource,等等),而后使用资源对象访问资源;一种是获取存在Spring应用上下文里的ResourceLoader之后,使用ResourceLoader加载资源,访问资源。第一种方式只需创建资源对象,调用资源对象的方法访问资源即可,这里不作介绍;对于第二种方式,Spring提供了这些支持:
1.ApplicationContextAware接口:实现ApplicationContextAware接口之后,我们的Bean就能拿到ApplicationContext。ApplicationContext是继承了ResourceLoader接口的。因此,能够调用ApplicationContext的getResource方法加载资源,访问资源。
2.自动装配ApplicationContext:通过自动装配把ApplicationContext装配到我们的Bean里,而后调用ApplicationContext的getResource方法加载资源,访问资源。
3.ResourceLoaderAware接口:实现ResourceLoaderAware接口之后,我们的Bean能够拿到ResourceLoader。之后,只要调用ResourceLoader的getResource方法就能加载资源,访问资源。ResourceLoaderAware接口定义如下:

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

4.自动装配ResourceLoader:通过自动装配把ResourceLoader装配到我们的Bean里,而后调用ResourceLoader的getResource方法加载资源,访问资源。

至此,关于资源访问的介绍告一段落。下一章,我们将会开始丰富Bean的配置。欢迎大家继续阅读,谢谢大家!

返回目录    下载代码

posted @ 2022-01-13 23:41  林雪波  阅读(151)  评论(0编辑  收藏  举报