9. 资源处理
Spring 框架提供了一种 org.springframework.core.io.ResourceLoader 抽象,用于从文件系统、Servlet 上下文和类路径中加载文件。Spring Cloud AWS 扩展了对 Amazon S3 服务的支持,通过资源加载器和 s3 协议实现资源的加载与写入。
资源加载器是上下文模块的一部分,因此无需额外依赖即可使用资源处理支持。
9.1. 配置资源加载器
Spring Cloud AWS 除非遇到带有 XML 命名空间元素的显式配置,否则不会修改默认的资源加载器。该配置包含一个用于整个应用上下文的元素,如下所示:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aws-context="http://www.springframework.org/schema/cloud/aws/context"
xsi:schemaLocation="http://www.springframework.org/schema/cloud/aws/context
http://www.springframework.org/schema/cloud/aws/context/spring-cloud-aws-context.xsd">
<aws-context:context-credentials>
...
</aws-context:context-credentials>
<aws-context:context-resource-loader/>
</beans>
9.2. 下载文件
下载文件可以通过使用 s3 协议来引用 Amazon S3 存储桶及其对象内的文件和对象。典型的模式是 s3://<bucket>/<object>,其中 bucket 是全局且唯一的存储桶名称,object 是存储桶内有效对象名称。该对象名称可以是存储桶根目录中的文件,也可以是存储桶内目录中的嵌套文件。
下例展示了如何使用资源加载程序来加载不同的资源。
public class SimpleResourceLoadingBean {
@Autowired
private ResourceLoader resourceLoader;
public void resourceLoadingMethod() throws IOException {
Resource resource = this.resourceLoader.getResource("s3://myBucket/rootFile.log");
Resource secondResource = this.resourceLoader.getResource("s3://myBucket/rootFolder/subFile");
InputStream inputStream = resource.getInputStream();
//read file
}
}
9.3. 上传文件
从 Spring 框架 3.1 开始,资源加载器也可以与 org.springframework.core.io.WritableResource 接口一起使用,该接口是 org.springframework.core.io.ResourceLoader 接口的特殊化。 客户端可以使用 WritableResource 接口上传文件。 下一个示例演示了使用资源加载程序上传资源。
public class SimpleResourceLoadingBean {
@Autowired
private ResourceLoader resourceLoader;
public void writeResource() throws IOException {
Resource resource = this.resourceLoader.getResource("s3://myBucket/rootFile.log");
WritableResource writableResource = (WritableResource) resource;
try (OutputStream outputStream = writableResource.getOutputStream()) {
outputStream.write("test".getBytes());
}
}
}
9.3.1. 上传多部分文件
Amazon S3 支持 多部分上传 来增加上传文件时的整体吞吐量。默认情况下,Spring Cloud AWS 只使用一个线程上传文件,因此不提供并行上传支持。用户可以为资源加载器配置自定义 org.springframework.core.task.TaskExecutor。资源加载器会同时在多个线程中排队,以便使用并行多部分上传。
Spring 框架的资源加载器的配置,上传时使用 10 个线程,如下所示
<beans ...>
<aws-context:context-resource-loader task-executor="executor" />
<task:executor id="executor" pool-size="10" queue-capacity="0" rejection-policy="CALLER_RUNS" />
</beans>
|
Spring Cloud AWS 每个线程占用高达 5 MB(最低)的内存。因此,每个并行线程在其堆中都会产生 5 MB 的内存足迹,如果有 10 个线程,则总共会占用高达 50 MB 的堆内存。Spring Cloud AWS 会尽早释放内存。上面的示例也显示没有配置 |
9.3.2. 使用 TransferManager 上传
Amazon SDK 还提供一个高级抽象,可用于上传文件,也可使用多部分功能上传多个线程。在应用程序代码中可以轻松创建一个 0,并使用已通过 Spring Cloud AWS 资源加载器配置创建的预配置 1 客户端注入它。
这个示例展示了在应用程序中使用transferManager来从硬盘上传文件的用法。
public class SimpleResourceLoadingBean {
@Autowired
private AmazonS3 amazonS3;
public void withTransferManager() {
TransferManager transferManager = new TransferManager(this.amazonS3);
transferManager.upload("myBucket","filename",new File("someFile"));
}
}
9.4.搜索资源
Spring 资源加载器还支持基于 Ant 样式路径规范收集资源。Spring Cloud AWS 为在整个存储桶中,甚至是跨存储桶查找资源提供相同的支持。在搜索 S3 存储桶的情况下,实际的资源加载器需要被包装在 Spring Cloud AWS 提供的一个里面,如果是非 S3 存储桶,资源加载器会回退到原始的那个。接下来的示例展示了通过使用不同的模式来显示资源分辨率。
public class SimpleResourceLoadingBean {
private ResourcePatternResolver resourcePatternResolver;
@Autowired
public void setupResolver(ApplicationContext applicationContext, AmazonS3 amazonS3){
this.resourcePatternResolver = new PathMatchingSimpleStorageResourcePatternResolver(amazonS3, applicationContext);
}
public void resolveAndLoad() throws IOException {
Resource[] allTxtFilesInFolder = this.resourcePatternResolver.getResources("s3://bucket/name/*.txt");
Resource[] allTxtFilesInBucket = this.resourcePatternResolver.getResources("s3://bucket/**/*.txt");
Resource[] allTxtFilesGlobally = this.resourcePatternResolver.getResources("s3://**/*.txt");
}
}
|
拥有的存储桶越多,遍历所有存储桶查找资源可能需要很长时间。 |
9.5. 使用CloudFormation
Spring Cloud也允许在堆栈创建期间创建存储桶。这些存储桶通常具有必须用作存储桶名称的生成名称。为了允许应用程序开发人员在其配置中定义静态名称,Spring Cloud AWS提供了支持解析根据逻辑名称生成的生成存储桶名称的功能。
应用程序开发人员可以使用org.springframework.cloud.aws.core.env.ResourceIdResolver接口根据逻辑名称解析生成的物理名称。
下一个示例显示了CloudFormation堆栈模板中的存储桶定义。该存储桶的名称将像integrationteststack-sampleBucket-23qysofs62tc2
{
"Resources": {
"sampleBucket": {
"Type": "AWS::S3::Bucket"
}
}
}
应用开发人员可以解析该名称并将其用于如下面的示例中所示加载资源。
public class SimpleResourceLoadingBean {
private final ResourceLoader loader;
private final ResourceIdResolver idResolver;
@Autowired
public SimpleResourceLoadingBean(ResourceLoader loader, ResourceIdResolver idResolver) {
this.loader = loader;
this.idResolver = idResolver;
}
public void resolveAndLoad() {
String sampleBucketName = this.idResolver.
resolveToPhysicalResourceId("sampleBucket");
Resource resource = this.loader.
getResource("s3://" + sampleBucketName + "/test");
}
}