使用Spring Reactor使用新的Java版Azure SDK异步上传图像

The new Azure SDK for Java

这篇博客文章使用即将推出的Java Azure SDK:在撰写本文时,它仍是预览版本,但是许多人已经开始使用它。

To be more precise, we are talking here of the Azure SDK for Java (August 2019 Preview), also seen as "1.0.0-preview.2" on Maven Central.

This new release is important as it uses some new, modern API guidelines, and also because its asynchronous features are powered by Spring Reactor.

这些新的响应式API有趣,因为它们提供了更好的可伸缩性,并且可以与Spring很好地协同工作。 不幸的是,它们是以使用一个API的代价为代价的,该API理解起来更加复杂,调试起来也更加复杂:这就是我们撰写此博客文章的原因!

The problem with uploading data

上载数据需要时间,并且通常需要良好的连接:如果您使用的是移动设备,这肯定是一个问题! 如果我们使用基于线程的模型,则意味着发送多个文件将阻塞多个线程,并且伸缩性不会很高。 或者,您可以将所有文件放在自己可以管理的队列中:这可能对代码来说相当复杂,并且这将阻止您并行上传这些文件,因此性能将不会很好。 这就是Spring Reactor发挥作用的地方!

这里的想法是以异步,非阻塞的方式上传数据,因此我们可以并行上传许多文件而不会阻塞系统。

Spring Reactor and Spring Webflux

请注意,这里的示例适用于Spring Webflux:这是Spring的响应版本,由于它的工作方式与经典的Spring MVC(基于线程)完全不同,因此该代码不适用于Spring MVC 。 这是进行反应式编程时的问题之一:混合反应式代码和基于线程的代码实际上是不可能的,因此您的所有项目都需要使用反应式API进行设计和思考。 我认为,这最适合于微服务架构,在该架构中,您将使用反应式API编写某些特定服务,而使用传统的基于线程的API编写某些服务。 响应式微服务的开发和调试可能会稍微复杂一些,但会提供更好的可伸缩性,启动时间,内存消耗,因此它们将用于某些特定的资源密集型任务。

Creating a Storage Account

In the the Azure portal, create a new storage account:

create a new storage account

创建完成后,转到该存储帐户并选择“共享访问签名”或SAS。 SAS是一种签名,它允许在有限的时间段内访问某些资源:非常适合在特定位置上载数据而不损害安全性。

单击“生成SAS和连接字符串”后,复制最后生成的文本字段,名称为“ Blob服务SAS URL”。 这是我们将与用于Java的Azure SDK一起使用的版本。

Blob service SAS URL

Add the Azure SDK for Java to the pom.xml

由于用于Java的Azure SDK预览位于Maven Central上,因此只需将依赖项添加到项目的pom.xml中即可:

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-storage-blob</artifactId>
    <version>12.0.0-preview.2</version>
</dependency>

Using the new asynchronous API

Let's first have a look at the final code, which is available on https://github.com/jdubois/jhipster-azure-blob-storage/blob/master/src/main/java/com/example/demo/PictureResource.java:

@RestController
@RequestMapping("/api")
public class PictureResource {

    Logger log = LoggerFactory.getLogger(PictureResource.class);

    @Value("${AZURE_BLOB_ENDPOINT}")
    private String endpoint;

    @PostMapping("/picture")
    public void uploadPicture() throws IOException {
        log.debug("Configuring storage client");
        BlobServiceAsyncClient client =  new BlobServiceClientBuilder()
            .endpoint(endpoint)
            .buildAsyncClient();

        client.createContainer("pictures")
            .doOnError((e) -> {
                log.info("Container already exists");
            })
            .flatMap(
                (clientResponse) -> {
                    log.info("Uploading picture");
                    return clientResponse
                        .value()
                        .getBlockBlobAsyncClient("picture.png")
                        .uploadFromFile("src/main/resources/image.png");
                })
            .subscribe();
    }
}

警告该API仅在使用Spring Reactive时有效,因此请注意,您需要在Spring Webflux项目中使用它,而不是Spring MVC项目中。

验证是使用我们上面复制的“ Blob服务SAS URL”完成的,并且使用AZURE_BLOB_ENDPOINT此示例中的环境变量:请注意,URL中包含SAS,因此不需要在其他地方进行身份验证(证书()API中的方法,这可能会产生误导,但对我们而言是无用的)。 因此,该URL应该安全地存储,并且不要与您的代码一起提交。

使用Spring Reactor API发送图像:

  • 我们创建一个特定的图片用于存储一些数据的容器然后,我们使用Spring Reactor的API上传图片最后,我们使用订阅()方法,使我们的代码异步运行

结果,此方法将很快返回,然后将在另一个线程中创建容器并上传图像。 这会使调试变得更加困难,但允许我们的应用程序接受更多请求,并以异步方式处理它们。

Improving the reactive code

This tip was provided by Christophe Bornet, many thanks to him!

前面的代码是我们通常在项目中看到的,但是为了使Spring Webflux处理。订阅()部分:这将保留Spring Webflux和Azure SDK之间的背压。 同样,这意味着错误将由Spring Webflux管理,而不是丢失:如果使用Azure SDK上传文件时发生错误,则使用此新代码将产生500个错误。

The change can be seen in this commit, where we replace the .subscribe() by a .then() and we return a Mono<Void> instead of not returning anything. It will be Spring Webflux's responsibility to handle that Mono and call .subscribe().

结果代码如下:

    @PostMapping("/picture")
    public Mono<Void> uploadPicture() throws IOException {
        log.debug("Configuring storage client");
        BlobServiceAsyncClient client =  new BlobServiceClientBuilder()
            .endpoint(endpoint)
            .buildAsyncClient();

        return client.createContainer("pictures")
            .doOnError((e) -> {
                log.info("Container already exists");
            })
            .flatMap(
                (clientResponse) -> {
                    log.info("Uploading picture");
                    return clientResponse
                        .value()
                        .getBlockBlobAsyncClient("picture.png")
                        .uploadFromFile("src/main/resources/image.png");
                })
            .then();
    }

它是反应式API的更高级用法,但结果值得付出麻烦。

Conclusion and feedback

当前,我们缺少有关适用于Java的Azure SDK中此新异步API的文档和示例。 我认为这在某些特定情况下非常重要,例如我们在这里遇到的情况,因为如果您要可伸缩的应用程序,通常不应在当前线程中上载或下载数据。

该SDK仍处于预览状态,因此,如果您对此API有任何反馈,请对此文章发表评论!

例如,当前的API允许您创建一个容器(如果容器已经存在,则将失败)或获取现有容器(如果容器尚不存在,则将失败)。 您是否认为应该有类似的选择getOrCreateContainer(“ name”),如果需要,它将自动创建一个容器?

from: https://dev.to//azure/using-the-new-azure-sdk-for-java-to-upload-images-asynchronously-using-spring-reactor-20ha

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值