org.springframework.core.io.Resource 为 Spring API 提供统一句柄,所表示的内容可以位于文件、
类路径条目、URL、servlet 上下文、字节数组或已打开的流中。
该抽象描述访问能力;它不会让每个资源都可寻址、可重复读取、可写或由文件支持。
Resource 契约
#
Resource 扩展了 InputStreamSource。getInputStream() 是基本操作,而
exists()、isReadable()、isOpen()、isFile()、contentLength()、
lastModified() 和 getDescription() 等方法暴露能力或元数据。
重要实现包括:
ClassPathResource:用于类加载器或类相对条目;FileSystemResource和PathResource:用于文件系统内容;UrlResource:用于 JVM 支持的 URL;ServletContextResource:用于 Web 应用路径;ByteArrayResource:用于可重复读取的内存字节;以及InputStreamResource:用于已打开的、通常只能使用一次的流。
调用方拥有 getInputStream() 返回的每个流,并必须关闭它。
isOpen() 尤其重要:InputStreamResource 包装已打开的句柄,不能安全地重复读取;
文件和字节数组资源则可以在每次调用时打开新流。
加载和相对解析 #
ResourceLoader.getResource(String) 将位置转换为一个资源。
每个 ApplicationContext 都是资源加载器。前缀选择明确语义:
classpath:com/example/report.html选择类路径资源。file:/srv/app/report.html选择文件系统 URL。https://example.net/schema.json选择 URL 资源。
无前缀位置相对于上下文。ClassPathXmlApplicationContext 将其解释为类路径位置,
FileSystemXmlApplicationContext 将其解释为文件系统位置,Web 应用上下文则将其解释为 servlet 上下文位置。
库代码应请求 Resource 或 ResourceLoader,而不是假设一种默认位置。
ResourcePatternResolver 将加载扩展到位置模式和多个匹配项。
classpath*: 搜索所有匹配的类路径根;Ant 风格通配符通过模式解析生效,
而不是通过单资源 ResourceLoader 契约生效。
注入资源 #
Spring 可以使用外围应用上下文作为加载器,将位置字符串转换为 Resource:
@Component
final class ReportRenderer {
private final Resource template;
ReportRenderer(@Value("${report.template:classpath:reports/daily.html}")
Resource template) {
this.template = template;
}
}构造器注入使依赖可见,并允许测试提供 ByteArrayResource。
当位置随操作变化时注入 ResourceLoader;只有应用确实有意接受多个匹配项时,
才注入 Resource[] 或 ResourcePatternResolver。
存在性、可重复读取和写入 #
exists() 是探测而不是预留;内容可能在打开前消失。
当正确性依赖访问成功时,优先打开资源并处理产生的 IOException。
元数据操作也可能需要 I/O,而远程 URL 可能缓慢或不可用。
WritableResource 增加 isWritable() 和 getOutputStream()。
FileSystemResource 和 PathResource 实现该接口,而打包 JAR 内的类路径资源不实现。
写入代码应要求 WritableResource,而不是根据位置字符串向下转型。
可重复性取决于具体实现。需要两遍处理的解析器可以将一次性资源缓冲为 ByteArrayResource,
并明确设置大小限制。API 应记录它们是打开一次、重新打开、保留还是关闭流,
从而保持资源所有权明确。
评论
在 GitHub 上阅读或评论(发表评论需要登录)