Spring Cloud Alibaba 分布式微服务高并发数据平台化(中台)思想+多租户saas企业开发架构之spring框架学习 - Resources

四、Resources
本章介绍 Spring 如何处理资源以及如何在 Spring 中使用资源。

1、介绍
不幸的是,Java 的标准 java.net.URL 类和各种 URL 前缀的标准处理程序不足以满足所有对低级资源的访问。 例如,没有标准化的 URL 实现可用于访问需要从类路径或相对于 ServletContext 获取的资源。 虽然可以为专门的 URL 前缀注册新的处理程序(类似于现有的前缀处理程序,例如 http:),但这通常相当复杂,而且 URL 接口仍然缺乏一些理想的功能,例如检查是否存在的方法 指向的资源。

需要架构源码的朋友可以看我个人简介联系我,架构源码

 

2、Resource 接口
Spring 的 Resource 接口位于 org.springframework.core.io 中。 包旨在成为一个更强大的接口,用于抽象对低级资源的访问。 以下清单提供了 Resource 接口的概述。 有关更多详细信息,请参阅资源 javadoc。

public interface Resource extends InputStreamSource {

    boolean exists();

    boolean isReadable();

    boolean isOpen();

    boolean isFile();

    URL getURL() throws IOException;

    URI getURI() throws IOException;

    File getFile() throws IOException;

    ReadableByteChannel readableChannel() throws IOException;

    long contentLength() throws IOException;

    long lastModified() throws IOException;

    Resource createRelative(String relativePath) throws IOException;

    String getFilename();

    String getDescription();
}


正如 Resource 接口的定义所示,它扩展了 InputStreamSource 接口。 以下清单显示了 InputStreamSource 接口的定义:

public interface InputStreamSource {

    InputStream getInputStream() throws IOException;
}


Resource 接口中一些最重要的方法是:

getInputStream():定位并打开资源,返回一个InputStream用于从资源中读取。 预计每次调用都会返回一个新的 InputStream。 关闭流是调用者的责任。
exists():返回一个布尔值,指示该资源是否以物理形式实际存在。
isOpen():返回一个布尔值,指示此资源是否表示具有打开流的句柄。 如果为 true,则 InputStream 不能被多次读取,必须只读取一次然后关闭以避免资源泄漏。 为所有常用资源实现返回 false,InputStreamResource 除外。
getDescription():返回此资源的描述,用于处理资源时的错误输出。 这通常是完全限定的文件名或资源的实际 URL。
其他方法可让您获取表示资源的实际 URL 或 File 对象(如果底层实现兼容并支持该功能)。

Resource 接口的一些实现还为支持写入的资源实现了扩展的 WritableResource 接口。

Spring 本身广泛使用 Resource 抽象,作为需要资源时许多方法签名中的参数类型。 某些 Spring API 中的其他方法(例如各种 ApplicationContext 实现的构造函数)采用一个字符串,该字符串以未修饰或简单的形式用于创建适合该上下文实现的资源,或者通过字符串路径上的特殊前缀,让调用者指定必须创建和使用特定的资源实现。

虽然 Resource 接口在 Spring 和 Spring 中被大量使用,但在自己的代码中单独用作通用实用程序类,用于访问资源实际上非常方便,即使您的代码不知道或不关心任何其他 Spring 的部分。 虽然这将您的代码与 Spring 耦合,但它实际上只是将它耦合到这一小组实用程序类,这些实用程序类可以作为 URL 的更强大替代品,并且可以被视为等效于您为此目的使用的任何其他库。

Resource 抽象不取代功能。 它在可能的情况下包装它。 例如,一个 UrlResource 包装一个 URL 并使用包装的 URL 来完成它的工作。

3、内置资源实现
Spring 包括几个内置的 Resource 实现:

UrlResource
ClassPathResource
FileSystemResource
PathResource
ServletContextResource
InputStreamResource
ByteArrayResource
有关 Spring 中可用的资源实现的完整列表,请参阅资源 javadoc 的“所有已知的实现类”部分。

3.1 UrlResource
UrlResource 包装了一个 java.net.URL,可用于访问通常可通过 URL 访问的任何对象,例如文件、HTTPS 目标、FTP 目标等。 所有 URL 都具有标准化的字符串表示形式,以便使用适当的标准化前缀来指示一种 URL 类型和另一种 URL 类型。 这包括 file:用于访问文件系统路径、https:用于通过 HTTPS 协议访问资源、ftp:用于通过 FTP 访问资源等。

UrlResource 是由 Java 代码通过显式使用 UrlResource 构造函数创建的,但通常在调用 API 方法时隐式创建,该方法采用表示路径的 String 参数。 对于后一种情况,JavaBeans PropertyEditor 最终决定创建哪种类型的资源。 如果路径字符串包含一个众所周知的(对于属性编辑器来说)前缀(例如 classpath:),它会为该前缀创建一个适当的专用资源。 但是,如果它不识别前缀,则假定该字符串是标准 URL 字符串并创建一个 UrlResource。

3.2 ClassPathResource
此类表示应从类路径中获取的资源。 它使用线程上下文类加载器、给定的类加载器或给定的类来加载资源。

如果类路径资源驻留在文件系统中,则此资源实现支持解析为 java.io.File,但不支持驻留在 jar 中且尚未(由 servlet 引擎或任何环境)扩展到文件系统。 为了解决这个问题,各种资源实现始终支持解析为 java.net.URL。

ClassPathResource 由 Java 代码通过显式使用 ClassPathResource 构造函数创建,但通常在调用 API 方法时隐式创建,该方法采用表示路径的 String 参数。 对于后一种情况,JavaBeans PropertyEditor 识别字符串路径上的特殊前缀 classpath:并在这种情况下创建 ClassPathResource。

3.3 FileSystemResource
这是 java.io.File 句柄的 Resource 实现。 它还支持 java.nio.file.Path 句柄,应用 Spring 的标准 String-based 路径转换,但通过 java.nio.file.Files API 执行所有操作。 对于纯基于 java.nio.path.Path 的支持,请改用 PathResource。 FileSystemResource 支持解析为文件和 URL。

3.4 PathResource
这是 java.nio.file.Path 句柄的 Resource 实现,通过 Path API 执行所有操作和转换。 它支持解析为文件和 URL,还实现了扩展的 WritableResource 接口。 PathResource 实际上是一个基于纯 java.nio.path.Path 的 FileSystemResource 替代品,具有不同的 createRelative 行为。

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

它始终支持流访问和 URL 访问,但仅当 Web 应用程序存档扩展且资源物理位于文件系统上时才允许 java.io.File 访问。 它是否在文件系统上扩展或直接从 JAR 或其他地方(如数据库)访问(这是可以想象的)实际上取决于 Servlet 容器。

3.6 InputStreamResource
InputStreamResource 是给定 InputStream 的 Resource 实现。 仅当没有适用的特定资源实现时才应使用它。 特别是,在可能的情况下,更喜欢 ByteArrayResource 或任何基于文件的 Resource 实现。

与其他 Resource 实现相反,这是一个已打开资源的描述符。 因此,它从 isOpen() 返回 true。 如果您需要将资源描述符保留在某处或需要多次读取流,请不要使用它。

3.7 ByteArrayResource
这是给定字节数组的资源实现。 它为给定的字节数组创建一个 ByteArrayInputStream。

对于从任何给定的字节数组加载内容非常有用,而不必求助于单一使用的 InputStreamResource。4、ResourceLoader 接口

ResourceLoader 接口旨在由可以返回(即加载)Resource 实例的对象实现。 以下清单显示了 ResourceLoader 接口定义:

public interface ResourceLoader {

    Resource getResource(String location);

    ClassLoader getClassLoader();
}


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

当您在特定应用程序上下文上调用 getResource() 并且指定的位置路径没有特定前缀时,您将返回适合该特定应用程序上下文的 Resource 类型。 例如,假设以下代码片段是针对 ClassPathXmlApplicationContext 实例运行的:

Resource template = ctx.getResource("some/resource/path/myTemplate.txt");


针对 ClassPathXmlApplicationContext,该代码返回一个 ClassPathResource。 如果对 FileSystemXmlApplicationContext 实例运行相同的方法,它将返回一个 FileSystemResource。 对于 WebApplicationContext,它将返回一个 ServletContextResource。 类似地,它会为每个上下文返回适当的对象。

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

另一方面,您还可以通过指定特殊的 classpath: 前缀来强制使用 ClassPathResource,而不管应用程序上下文类型如何,如下例所示:

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");


同样,您可以通过指定任何标准 java.net.URL 前缀来强制使用 UrlResource。 以下示例使用 file 和 https 前缀:

Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");

Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");


下表总结了将 String 对象转换为 Resource 对象的策略:

refix    Example    Explanation
classpath:    classpath:com/myapp/config.xml    从类路径加载。
file:    file:///data/config.xml    从文件系统加载为“URL”。
https:    https://myserver/logo.png    加载为“URL”。
(none)    /data/config.xml    取决于底层的“ApplicationContext”。
5、ResourcePatternResolver 接口
ResourcePatternResolver 接口是 ResourceLoader 接口的扩展,它定义了将位置模式(例如,Ant 风格的路径模式)解析为 Resource 对象的策略。

public interface ResourcePatternResolver extends ResourceLoader {

    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    Resource[] getResources(String locationPattern) throws IOException;
}


从上面可以看出,这个接口还定义了一个特殊的 classpath*: 资源前缀,用于所有匹配的类路径资源。 请注意,在这种情况下,资源位置应该是没有占位符的路径 — 例如,classpath*:/config/beans.xml。 JAR 文件或类路径中的不同目录可以包含多个具有相同路径和相同名称的文件。 有关使用 classpath*: 资源前缀的通配符支持的更多详细信息,请参阅 Application Context Constructor Resource Paths 及其小节中的通配符。

可以检查传入的 ResourceLoader(例如,通过 ResourceLoaderAware语义提供的)是否也实现了此扩展接口。

PathMatchingResourcePatternResolver 是一个独立的实现,可以在 ApplicationContext 之外使用,也被 ResourceArrayPropertyEditor 用于填充 Resource[] bean 属性。 PathMatchingResourcePatternResolver 能够将指定的资源位置路径解析为一个或多个匹配的 Resource 对象。 源路径可能是一个简单的路径,它具有到目标资源的一对一映射,或者可能包含特殊的 classpath*: 前缀和/或内部 Ant 样式的正则表达式(使用 Spring 的 org.springframework.util 匹配 .AntPathMatcher 实用程序)。 后者都是有效的通配符。

任何标准 ApplicationContext 中的默认 ResourceLoader 实际上是 PathMatchingResourcePatternResolver 的一个实例,它实现了 ResourcePatternResolver 接口。 ApplicationContext 实例本身也是如此,它也实现了 ResourcePatternResolver 接口并委托给默认的 PathMatchingResourcePatternResolver。

6、ResourceLoaderAware 接口
ResourceLoaderAware 接口是一个特殊的回调接口,用于标识期望提供 ResourceLoader 引用的组件。 以下清单显示了 ResourceLoaderAware接口的定义:

public interface ResourceLoaderAware {

    void setResourceLoader(ResourceLoader resourceLoader);
}


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

由于 ApplicationContext 是一个 ResourceLoader,因此 bean 还可以实现 ApplicationContextAware 接口并直接使用提供的应用程序上下文来加载资源。 但是,一般而言,如果您只需要使用专门的 ResourceLoader 接口,则效果会更好。 代码将只耦合到资源加载接口(可以被认为是一个实用程序接口)而不是整个 Spring ApplicationContext 接口。

在应用程序组件中,您还可以依靠 ResourceLoader的自动装配作为实现 ResourceLoaderAware 接口的替代方法。 传统的构造函数和 byType 自动装配模式(如 Autowiring Collaborators 中所述)能够分别为构造函数参数或 setter 方法参数提供 ResourceLoader。 为了获得更大的灵活性(包括自动装配字段和多参数方法的能力),请考虑使用基于注解的自动装配功能。 在这种情况下,只要相关字段、构造函数或方法带有 @Autowired 注解,ResourceLoader 就会自动装配到需要 ResourceLoader 类型的字段、构造函数参数或方法参数中。 有关更多信息,请参阅使用 @Autowired。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值