资源访问(Resource access)

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

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

我们把文件路径 resources\\app-config.xml 交给ClassPathXmlApplicationContext,ClassPathXmlApplicationContext就能基于类路径加载app-config.xml配置文件。事情出奇地简单!可在简单的背后,却深藏着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类型的对象,使用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的配置。欢迎大家继续阅读,谢谢大家!

返回目录    下载代码

————————

Classpathxmlapplicationcontext is one of the implementations of spring application context. Its instances can usually be created as follows:

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

Let’s put the file path , resources \ \ app config XML} to the classpathxmlapplicationcontext, the classpathxmlapplicationcontext can load app config based on the classpath XML configuration file. Things are surprisingly simple! But behind the simplicity, there is a hidden effort of the spring application context. Resource access is one of them.

As we all know, spring application context implements the ApplicationContext interface. The ApplicationContext interface inherits the resourceloader interface and can load resources such as XML configuration files. Naturally, the spring application context that implements the ApplicationContext interface has the ability to load resources such as XML configuration files. The resourceloader interface is defined as follows:

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

This interface only defines the resource getresource (string location) method, which can create a resource type object to return after accepting the resource path. Resource is a resource interface defined by spring. It has the following common resource access methods:
1. InputStream getInputStream() 
After opening the resource, create and return Java io. An object of type InputStream for the caller to read resources as a data stream. Note: each call to this method creates and returns an object of type InputStream. Remember to turn it off after use to avoid memory leakage.
2. File getFile() 
Get Java io. File type objects can provide information such as file location, file size, and file read-write permissions.
3. String getFilename() 
Gets the file name of the resource.
4. String getDescription() 
Get the description information of the resource, usually including the full path of the resource.
5. boolean exists() 
Check if the resource exists.

Resource has several implementations, including the following:
1.UrlResource
This implementation simply encapsulates Java in the java basic class library net. URL。 Therefore, urlresource can do what URL can do.
2.ClassPathResource
Load resources based on classpath.
3.FileSystemResource
Loads resources based on the current working directory of the application.
4.ServletContextResource
Load resources based on the web application root directory. Obviously, this implementation is linked to the web application.

You can see that there are four common resource implementations. When different spring application contexts implement the resourceloader interface, the resource types created are different. The correspondence is as follows:
1. Classpathxmlapplicationcontext creates a resource of type classpathresource.
2. Filesystemxmlapplicationcontext creates a resource of type filesystemresource.
3. Xmlwebapplicationcontext creates a resource of type servletcontextresource.

So we know that the process of loading the XML configuration file by the spring application context is as follows: after the spring application context completes the creation of the instance, it will call the resourceloader interface to create the resource type object, and use the resource type object to load the XML configuration file. If the spring application context is classpathxmlapplicationcontext, the created resource is classpathresource, which can load XML configuration files based on the classpath; If the spring application context is filesystemxmlapplicationcontext, the created resource is filesystemresource, which can load XML configuration files based on the current working directory of the application; If the spring application context is xmlwebapplicationcontext, the created resource is servletcontextresource, which can load XML configuration files based on the web application root directory.

In addition, we can specify the file path to create the spring application context as follows:

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

As you can see, the file path we passed to the spring application context has not only changed, but also added a mysterious prefix “file: to it.

What’s going on?

Originally, when creating resources, resourceloader will first check whether the file path has a prefix. If there is no prefix, the resource corresponding to the spring application context mentioned above will be created; If there are prefixes, different resources will be created according to different prefixes. This means that we can change the type of resource through prefix, so as to change the way spring application context loads XML configuration files.

Currently, the supported prefixes are: classpath:, file:, http:, FTP:. If you specify classpath:, a classpathresource will be created to load resources based on the classpath. If you specify file:, http:, or FTP:, a urlresource will be created to use Java net. Load resources as URLs. This means that if you specify file:, you can specify the relative path or absolute path of the resource after the prefix to load the resource; If http: or FTP: is specified, the location of network resources can be specified after the prefix to load network resources.

We can see that the introduction of prefix makes the loading of resources very flexible. We can change the loading mode of resources by adding prefix at any time. So, does the spring application context also support loading xml configuration files in the form of wildcards, making things more convenient?

The answer is yes. The spring application context supports ant style wildcards. In fact, before the spring application context calls resourceloader to load resources, it will first parse the wildcard to find out all matching file paths. After that, the spring application context circularly calls resourceloader with the matching file path as the parameter to complete the loading of resources. The following are ant style wildcards supported by the spring application context:

通配符

用途

示例

?

匹配任意一个字符

带有通配符的路径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

< strong > wildcard < / strong >

用途

示例

?

Match any character

*

Match zero or more characters

**

Match zero or more directories

So far, we have figured out how the spring application context loads resources such as XML configuration files. The problem is that XML configuration files are resources, PNG format pictures are resources, and word documents are also resources. What if we want to access resources such as pictures in PNG format?

Generally speaking, there are two ways to access such resources: one is to manually create resource objects (such as urlresource, classpathresource, filesystemresource, servletcontextresource, etc.) and then use resource objects to access resources; One is to use the resourceloader to load resources and access resources after obtaining the resourceloader existing in the spring application context. The first method only needs to create a resource object and call the method of the resource object to access the resource, which is not introduced here; For the second method, spring provides these supports:
1. Applicationcontextaware interface
After implementing the applicationcontextaware interface, our bean can get the ApplicationContext. ApplicationContext inherits the resourceloader interface. Therefore, we can call the getresource method of ApplicationContext to load resources and access resources.
2. Automatically assemble ApplicationContext
Assemble ApplicationContext into our Bean through automatic assembly, then call ApplicationContext’s getResource method to load resources and access resources.
3. Resourceloaderaware interface
After implementing the resourceloaderaware interface, our bean can get the resourceloader. After that, just call the getresource method of resourceloader to load resources and access resources. The resourceloaderaware interface is defined as follows:

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

4. Automatically assemble resourceloader
Assemble the resourceloader into our bean through automatic assembly. Then the getResource method of ResourceLoader can be invoked to load resources and access resources.

So far, the introduction to resource access has come to an end. In the next chapter, we will begin to enrich the bean configuration. Welcome to continue reading, thank you!

Return to directory} download code