购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.4 资源处理

Java的标准java.net.URL类和各种以URL为前缀的标准处理程序(如URLDecoder、URLEncoder)并不足以满足所有对低级资源的访问。例如,想要访问需要从类路径获取的资源,或者相对于ServletContext的资源,标准的URL实现并不能支持。

Spring Resource接口就是为了弥补上述不足。

3.4.1 常用资源接口

Spring Resource接口是强大的用于访问低级资源的抽象,主要包含以下方法。

(1)getInputStream():定位并打开资源,返回一个从资源读取的InputStream。预计每个调用都会返回一个新的InputStream。调用方在使用完这个流后,关闭该流。

(2)exists():返回一个布尔值,指示这个资源是否实际上以物理形式存在。

(3)isOpen():返回一个布尔值,指示这个资源是否代表一个打开流的句柄。如果返回值为true,则只能读取一次InputStream,然后关闭,以避免资源泄露。除InputStreamResource外,对于所有的资源实现,都将返回false。

(4)getDescription():返回此资源的描述。这通常是完全限定的文件名或资源的实际URL。

其他方法允许开发人员获取表示资源的实际URL或File对象(如果底层实现是兼容的,并且支持该功能)。

资源抽象在Spring中被广泛使用。

3.4.2 内置资源接口实现

Spring提供了很多资源接口实现,这些实现是可以直接用的。

1.UrlResource

UrlResource封装了一个java.net.URL,用来访问可以通过URL访问的任何对象,如文件、HTTP目标、FTP目标等。所有的URL都由一个标准化的字符串表示,如使用适当的标准化前缀来表示另一个URL类型。

(1)file:用于访问文件系统路径。

(2)http:用于通过HTTP访问资源。

(3)ftp:用于通过FTP访问资源。

UrlResource是由Java代码使用UrlResource构造函数显式创建的,但是当调用一个接收String参数的API方法时,通常会隐式地创建UrlResource来表示路径。对于后一种情况,JavaBean PropertyEditor将最终决定创建哪种类型的资源。如果路径字符串中包含JavaBean PropertyEditor可以识别的前缀,如classpath:,那么它将为该前缀创建适当的专用资源。但是,如果不能识别前缀,它会认为这只是一个标准的URL字符串,并会创建一个UrlResource。

2.ClassPathResource

资源提取码:36642

ClassPathResource类代表一个应该从类路径中获得的资源,如使用线程上下文类加载器、给定的类加载器或给定的类来加载资源。如果类路径资源驻留在文件系统中,则此资源实现支持的解析为java.io.File。

ClassPathResource是由Java代码使用ClassPathResource构造函数显式创建的,但是当开发人员调用一个带有String参数的API方法时,通常会隐式地创建ClassPathResource来表示路径。对于后一种情况,JavaBean PropertyEditor将识别字符串路径上的特殊前缀classpath:,并在此情况下创建一个ClassPathResource。

3.FileSystemResource

FileSystemResource用于处理java.io.File资源的实现。

4.ServletContextResource

ServletContextResource是ServletContext资源的实现,解释相关Web应用程序根目录中的相对路径。

ServletContextResource总是支持流访问和URL访问,但只有在Web应用程序归档文件被扩展且资源位于文件系统中时才允许访问java.io.File。不管它是否被扩展,实际上都依赖于Servlet容器。

5.InputStreamResource

InputStreamResource给定InputStream的资源实现,只有在没有适用的资源实现的情况下才能使用。一般情况下,首选ByteArrayResource或任何基于文件的资源实现。

与其他Resource实现相比,InputStreamResource是已打开资源的描述符,因此isOpen()将返回true。如果需要将资源描述符保存在某处,或者需要多次读取流,就不要使用它。

6.ByteArrayResource

ByteArrayResource是给定字节数组的资源实现,它为给定的字节数组创建一个ByteArrayInput-Stream。

从任何给定的字节数组中加载内容都是很有用的,这样可以不必求助于一次性的InputStream-Resource。

3.4.3 ResourceLoader

ResourceLoader接口是由可以返回(加载)Resource实例的对象来实现的,该接口包含如下方法。

所有应用程序上下文都实现了ResourceLoader接口,因此所有的应用程序上下文都可以用来获取Resource实例。

当在特定的应用程序上下文中调用getResource()方法,并且指定的位置路径没有特定的前缀时,将返回适合该特定应用程序上下文的资源类型。例如,假设下面的代码是针对ClassPathXml-ApplicationContext实例执行的。

上述代码将返回一个ClassPathResource。如果对FileSystemXmlApplicationContext实例执行相同的方法,则会返回FileSystemResource。对于一个WebApplicationContext,开发人员会得到一个ServletContextResource,以此类推。

因此,可以选择适合特定应用程序上下文的方式加载资源。

另外,也可以通过指定特殊的前缀来强制使用特定的资源,而不管应用程序的上下文类型如何。例如:

3.4.4 ResourceLoaderAware

ResourceLoaderAware接口是一个特殊的标记接口,用于标识期望通过ResourceLoader接口提供的对象:

当一个类实现了ResourceLoaderAware并被部署到一个应用程序上下文(作为一个Spring管理的bean)时,它会被应用程序上下文识别为ResourceLoaderAware。然后应用程序上下文将调用setResourceLoader(ResourceLoader),并将ResourceLoader自身作为参数(记住,Spring中的所有应用程序上下文实现均使用ResourceLoader接口)。

由于ApplicationContext是一个ResourceLoader,因此bean也可以实现ApplicationContextAware接口,并直接使用提供的应用程序上下文来加载资源。但通常情况下,最好使用专用的ResourceLoader接口(如果有需要)。代码只会耦合到资源加载接口,它可以被认为是一个实用接口,而不是整个Spring ApplicationContext接口。

从Spring 2.5开始,开发人员可以依靠ResourceLoader的自动装配来实现ResourceLoader-Aware接口。传统的constructor和byType自动装配模式可以分别为构造函数参数和设置方法参数提供ResourceLoader类型的依赖关系。

3.4.5 资源作为依赖

如果bean本身要通过某种动态的过程来确定和提供资源路径,那么bean可能会使用ResourceLoader接口来加载资源。考虑加载某种类型的模板时,其中需要的特定资源取决于用户的角色。如果资源是静态的,那么完全清除ResourceLoader接口是有意义的,只要让bean公开其需要的Resource属性,并期望它们被注入其中,具体示例为:

注意,资源路径没有前缀,因为应用程序上下文本身将被用作ResourceLoader,所以根据上下文的确切类型,资源本身将根据需要通过ClassPathResource、FileSystemResource或ServletContext-Resource来进行加载。

如果需要强制使用特定的资源类型,则可以使用前缀。以下两个示例展示了如何强制使用ClassPathResource和UrlResource(后者用于访问文件系统)。 QUvK9mMtn8SvQqOGJ37EXClKpnzY4byo1lz5GMy7zK9PTELN0j8MSpoeA7X8cKFn

点击中间区域
呼出菜单
上一章
目录
下一章
×