领先一步
VMware 提供培训和认证,以加速您的进步。
了解更多这是关于面向 Spring 开发人员的 Microsoft Azure 的一个 6 部分系列的第 5 部分,每周一和周四发布新文章。如果没有微软的 Asir Vedamuthu Selvasingh、Yitao Dong、Bruno Borges、Brian Benz 和 Theresa Nguyen 的投入,我将无法完成此项工作。您可以在 Github 上找到本系列的代码。在您阅读这些内容时,可以通过 Twitter (@starbuxman)向我提出任何反馈或问题。您还可以在我的 Spring Tips (@SpringTipsLive) 系列文章 Bootiful Azure 中了解有关 Microsoft Azure 的更多信息。
以下是所有部分
现在让我们转向一些更……普通的东西。理想情况下,您甚至不必经常考虑这些东西。应用程序通常有存储需求:它们可能需要存储上传的用户内容(如图片或文档等二进制数据)、生成的工件(如 PDF 文件、视频、音乐等)。它们可能希望存储日志。不难想到应用程序可能想要持久存储的东西。
这些应用程序可以使用文件系统,例如本地计算机上的文件系统或网络附加文件系统,例如 NFS(网络文件系统)。我将使用 NFS 来泛指任何网络附加文件系统,例如 Samba、NFS(使用 NFS 协议挂载的文件系统)本身,或旧版选项(如 DAC、FAL 等)。NFS 选项为文件提供类似文件系统的接口,通常采用分层格式。NFS 选项很有趣,因为它们类似于我们都熟悉的文件系统,而且每个人都知道如何使用文件系统,对吧?当然,所有内容都看起来像 Windows 资源管理器中表达的层次结构?或者 macOS Finder?除了,它们看起来完全不一样……
仔细想想,当我说 NFS 选项类似于文件系统时,我不得不加上“类似”。有些支持比其他更细致的权限模型。有些支持对附加到树中文件和目录的元数据进行编码和复制。支持为不同的操作提供不同的速度保证;某些文件系统可能会针对读取或写入进行优化。有些可能会针对目录遍历进行优化。根据使用的客户端,客户端对文件读取或写入的看法是不同的。(写入是否立即在所有复制节点上保持一致?)
即使我们假设我们想要写入的所有文件系统都与 POSIX 兼容 - 您可以使用int open(const char *path, int flags)
或java.io.File
- 对于我们的客户端来说,情况可能并非如此。如果客户端不“理解”文件系统,而希望以其他方式操作数据怎么办?如果客户端只能使用 HTTP 协议呢?或者如果它希望使用 Bittorrent 通过对等网络更有效地合并下载呢?
出于这些原因以及更多其他原因,Amazon Web Services 引入了 S3,即简单云存储服务(明白了吗?“S”乘以 3?“S3”?)它已成为所有其他云供应商都需要支持的一种普遍标准。对于 Microsoft Azure,对象存储服务 (OSS) 是提供类似 S3 体验的事物。它不是 POSIX 文件系统。您可以直接使用其 API,就像我们在这里一样,但您也可以使用 S3Proxy 使用 AWS S3 客户端代理写入 OSS,其中有无数个!Azure 的对象存储服务确实很无聊,这正是您在处理像文件式数据的持久卷这样基础事物时所希望的。它甚至提供了一个名为 Microsoft Azure 存储资源管理器 的独立浏览器,它(没错!)可以在 Linux、Macintosh 和 Windows 上运行。该独立浏览器允许您以及 CosmosDB 数据一起查询 OSS 存储。这是否足够方便?您当然可以使用az
CLI 或 API 本身。我们将使用 Spring 集成来使用 Java API。
您必须创建一个分配给现有资源组bootiful
的 Azure 对象存储服务帐户 (bootiful
)。然后,创建一个分配给刚刚创建的存储帐户的存储容器 (files
)。以下是一个示例脚本。
#!/usr/bin/env bash
rg=$1
accountname=bootiful
az storage account create --name ${accountname} --resource-group ${rg}
az storage container create -n files --account-name ${accountname}
使用以下命令确定连接到应用程序所需的连接字符串。
az storage account show-connection-string --resource-group bootiful --name bootiful
请注意以后要使用的连接字符串。
将com.microsoft.azure
: azure-storage-spring-boot-starter
添加到应用程序的构建文件中。确保您已为azure.storage.connection-string
属性指定了 OSS 连接字符串。
我们将读取应用程序src/main/resources
目录中猫的图像的字节,然后将这些字节作为“块 Blob”写入对象存储服务。您可以通过其他接口与 OSS 交互,但出于我们的目的,将其视为“容器”(事物的逻辑分组,几乎类似于 S3 中的目录或存储桶)和“Blob”的集合非常自然。Blob 本质上是一个文件,具有与其关联的名称和元数据。以下示例所做的全部工作就是将猫的照片的字节存储到名为files
的容器中,其名称以cat-
为前缀,以.jpg
为后缀。
package com.example.bootifulazure;
import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.UUID;
@Log4j2
@Component
class ObjectStorageServiceDemo {
private final CloudStorageAccount cloudStorageAccount;
private final Resource resource;
private final CloudBlobContainer files;
ObjectStorageServiceDemo(
CloudStorageAccount csa,
@Value("classpath:/cat.jpg") Resource cat) throws URISyntaxException, StorageException {
this.resource = cat;
this.cloudStorageAccount = csa;
this.files = this.cloudStorageAccount
.createCloudBlobClient()
.getContainerReference("files");
}
@EventListener(ApplicationReadyEvent.class)
public void demo() throws Exception {
CloudBlockBlob blockBlobReference = this.files.getBlockBlobReference("cat-" + UUID.randomUUID().toString() + ".jpg");
try (InputStream in = this.resource.getInputStream()) {
blockBlobReference.upload(in, this.resource.contentLength());
log.info("uploaded blockblob to " + blockBlobReference.getStorageUri());
}
}
}
Microsoft Azure 特定的部分并非微不足道。我们获取对容器的引用,然后写入它,然后记录资源的可寻址 URI。多么普通!这正是您在像文件系统这样的计算系统原语中想要的。它应该是普通的。说实话,我更高兴能够使用 Java 7 的 try-with-resources 语法来处理Autocloseable
InputStream
引用!