В мире Java есть несколько хороших способов загрузки контента в корзину S3 — в этой статье мы рассмотрим, что предоставляет для этой цели библиотека jclouds .
Чтобы использовать jclouds — в частности, API, обсуждаемые в этой статье, эту простую зависимость Maven следует добавить в pom проекта:
<dependency>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-allblobstore</artifactId>
<version>1.5.10</version>
</dependency>
1. Загрузка на Amazon S3
Первым шагом для доступа к любому из этих API является создание BlobStoreContext
:
BlobStoreContext context =
ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
.buildView(BlobStoreContext.class);
Это представляет собой точку входа в общую службу хранения ключей и значений, такую как Amazon S3, но не ограничиваясь ею.
Для более конкретной реализации только S3 контекст можно создать аналогичным образом:
BlobStoreContext context =
ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
.buildView(S3BlobStoreContext.class);
А еще конкретнее:
BlobStoreContext context =
ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
.buildView(AWSS3BlobStoreContext.class);
Когда аутентифицированный контекст больше не нужен, его закрытие требуется для высвобождения всех связанных с ним ресурсов — потоков и соединений.
2. Четыре S3 API jclouds
Библиотека jclouds предоставляет четыре разных API для загрузки контента в корзину S3, от простого, но негибкого до сложного и мощного, все они получены через BlobStoreContext
. Начнем с самого простого.
2.1. Загрузить через Map
API
Самый простой способ использования jclouds для взаимодействия с корзиной S3 — представление этой корзины в виде карты. API получается из контекста:
InputStreamMap bucket = context.createInputStreamMap("bucketName");
Затем, чтобы загрузить простой файл HTML:
bucket.putString("index1.html", "<html><body>hello world1</body></html>");
API InputStreamMap
предоставляет несколько других типов операций PUT — файлы, необработанные байты — как для одиночных, так и для массовых операций.
В качестве примера можно использовать простой интеграционный тест:
@Test
public void whenFileIsUploadedToS3WithMapApi_thenNoExceptions() {
BlobStoreContext context =
ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
.buildView(AWSS3BlobStoreContext.class);
InputStreamMap bucket = context.createInputStreamMap("bucketName");
bucket.putString("index1.html", "<html><body>hello world1</body></html>");
context.close();
}
2.2. Загрузить через BlobMap
Использование простого Map API является простым, но в конечном итоге ограниченным — например, нет возможности передать метаданные о загружаемом контенте. Когда требуется больше гибкости и настройки, этого упрощенного подхода к загрузке данных в S3 через карту уже недостаточно.
Следующий API, который мы рассмотрим, — это API Blob Map — он получен из контекста:
BlobMap bucket = context.createBlobMap("bucketName");
API позволяет клиенту получить доступ к более низкоуровневым данным, таким как Content
— Length
, Content-Type
, Content-Encoding
, хэш eTag
и другие; чтобы загрузить новый контент в корзину:
Blob blob = bucket.blobBuilder().name("index2.html").
payload("<html><body>hello world2</body></html>").
contentType("text/html").calculateMD5().build();
API также позволяет устанавливать различные полезные нагрузки в запросе на создание.
Простой интеграционный тест для загрузки базового HTML-файла в S3 через API Blob Map:
@Test
public void whenFileIsUploadedToS3WithBlobMap_thenNoExceptions() throws IOException {
BlobStoreContext context =
ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
.buildView(AWSS3BlobStoreContext.class);
BlobMap bucket = context.createBlobMap("bucketName");
Blob blob = bucket.blobBuilder().name("index2.html").
payload("<html><body>hello world2</body></html>").
contentType("text/html").calculateMD5().build();
bucket.put(blob.getMetadata().getName(), blob);
context.close();
}
2.3. Загрузить через BlobStore
В предыдущих API не было возможности загружать контент с помощью многокомпонентной загрузки — это делало их плохо подходящими для работы с большими файлами. Это ограничение устранено с помощью следующего API, который мы собираемся рассмотреть, — синхронного API BlobStore.
Это получается из контекста:
BlobStore blobStore = context.getBlobStore();
Чтобы использовать поддержку составных частей и загрузить файл на S3:
Blob blob = blobStore.blobBuilder("index3.html").
payload("<html><body>hello world3</body></html>").contentType("text/html").build();
blobStore.putBlob("bucketName", blob, PutOptions.Builder.multipart());
Построитель полезной нагрузки — это тот же самый, который использовался BlobMap
API, поэтому здесь доступна та же гибкость в указании метаданных более низкого уровня о большом двоичном объекте. Разница заключается в том, что PutOptions
поддерживается операцией PUT API, а именно поддержкой составных частей .
Предыдущий интеграционный тест теперь включает несколько частей:
@Test
public void whenFileIsUploadedToS3WithBlobStore_thenNoExceptions() {
BlobStoreContext context =
ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
.buildView(AWSS3BlobStoreContext.class);
BlobStore blobStore = context.getBlobStore();
Blob blob = blobStore.blobBuilder("index3.html").
payload("<html><body>hello world3</body></html>").contentType("text/html").build();
blobStore.putBlob("bucketName", blob, PutOptions.Builder.multipart());
context.close();
}
2.4. Загрузить через AsyncBlobStore
Хотя предыдущий API BlobStore был синхронным, существует также асинхронный API для BlobStore
— AsyncBlobStore
. API аналогично получается из контекста:
AsyncBlobStore blobStore = context.getAsyncBlobStore();
Единственная разница между ними заключается в том, что асинхронный API возвращает ListenableFuture
для асинхронной операции PUT
:
Blob blob = blobStore.blobBuilder("index4.html").
.payload("<html><body>hello world4</body></html>").build();
blobStore.putBlob("bucketName", blob)<strong>.get()</strong>;
Интеграционный тест, отображающий эту операцию, аналогичен синхронному:
@Test
public void whenFileIsUploadedToS3WithBlobStore_thenNoExceptions() {
BlobStoreContext context =
ContextBuilder.newBuilder("aws-s3").credentials(identity, credentials)
.buildView(AWSS3BlobStoreContext.class);
BlobStore blobStore = context.getBlobStore();
Blob blob = blobStore.blobBuilder("index4.html").
payload("<html><body>hello world4</body></html>").contentType("text/html").build();
Future<String> putOp = blobStore.putBlob("bucketName", blob, PutOptions.Builder.multipart());
putOp.get();
context.close();
}
3. Заключение
В этой статье мы проанализировали четыре API , которые библиотека jclouds предоставляет для загрузки контента в Amazon S3. Эти четыре API являются универсальными и работают также с другими службами хранения ключей и значений, например, с хранилищем Microsoft Azure.
В следующей статье мы рассмотрим специфичный для Amazon S3 API, доступный в jclouds — AWSS3Client
. Реализуем операцию загрузки большого файла, динамически рассчитаем оптимальное количество частей для любого заданного файла и выполним загрузку всех частей параллельно.