- はじめに
- S3 SDK 利用の流れ
- クレデンシャル
- S3クライアントの作成
- オブジェクトのアップロード
- オブジェクトの取得
- オブジェクトの一覧
- オブジェクトの削除
- S3 Transfer Manager
- S3 Transfer Manager によるアップロード
- S3 Transfer Manager によるダウンロード
- S3 Transfer Manager によるディレクトリアップロード
- S3 Transfer Manager による全オブジェクトダウンロード
はじめに
S3 の SDK を久しぶりに見たら、バージョンが2系になり、1系とはガラッと作り替えられていたので、簡単な使い方をメモしておきます。
旧来の com.amazonaws:aws-java-sdk-s3
とはグループID・アーティファクトIDが変わり、以下の 依存となります。
implementation("software.amazon.awssdk:s3:2.20.+")
他のSDKと合わせてバージョン更新されるので、パッチバージョンはすごい勢いで上がります。
他のSDKも使う場合には、BOMがあるので以下のように定義できます。
dependencies { implementation platform('software.amazon.awssdk:bom:2.20.+') implementation 'software.amazon.awssdk:s3:' }
バージョン1の時は、単にクライアントのメソッド呼び出しで結果を受け取る形でしたが、バージョン2からは、それぞれの操作に応じたリクエストオブジェクトを介して操作するようになりました。
バージョン2では、独自の HTTP クライアントを設定、ノンブロッキングI/Oのサポート、レスポンスのページ分割などの機能が含まれています。
利用例は以下が参考になります。
S3 SDK 利用の流れ
S3 SDKは、概ね以下の流れで操作します。
// クレデンシャル ProfileCredentialsProvider credentialsProvider = ProfileCredentialsProvider.create(); // クライアント生成 S3Client s3 = S3Client.builder() .region(Region.AP_NORTHEAST_1) .credentialsProvider(credentialsProvider) .build(); // リクエスト生成 ListObjectsRequest listObjects = ListObjectsRequest.builder() .bucket(bucketName) .build(); // 実行してレスポンス取得 ListObjectsResponse res = s3.listObjects(listObjects); for (S3Object obj : res.contents()) { ... }
上記のリクエスト生成はラムダで以下のように書くことができます。
s3.listObjects(req -> req.bucket(bucketName));
多くはこちらのラムダ形式で書くことになるでしょう。
クレデンシャル
クレデンシャルは AwsCredentialsProvider
インスタンスを介して設定します。
IAMユーザのアクセスキーとシークレットアクセスキーで認証を行うには AwsBasicCredentials
から AwsCredentialsProvider
を生成します。
AwsCredentials credentials = AwsBasicCredentials.create(accessKeyId, secretAccessKey); AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(credentials);
クレデンシャルを指定しない場合は、DefaultCredentialsProvider
が使われます。
DefaultCredentialsProvider
では、以下の様に定義されたプロバイダに対して、上から順に認証情報を検索し、最初に見つかったものから AwsCredentialsProvider
が生成されます。
AwsCredentialsProvider[] credentialsProviders = new AwsCredentialsProvider[] { SystemPropertyCredentialsProvider.create(), // 1. Javaシステムプロパティ EnvironmentVariableCredentialsProvider.create(), // 2. 環境変数 WebIdentityTokenFileCredentialsProvider.builder() // 3. ウェブアイデンティティトークン .asyncCredentialUpdateEnabled(asyncCredentialUpdateEnabled) .build(), ProfileCredentialsProvider.builder() // 4. 共有 credentials と config ファイル .profileFile(builder.profileFile) .profileName(builder.profileName) .build(), ContainerCredentialsProvider.builder() // 5. Amazon ECS コンテナ認証情報 .asyncCredentialUpdateEnabled(asyncCredentialUpdateEnabled) .build(), InstanceProfileCredentialsProvider.builder() // 6. Amazon EC2メタデータサービス .asyncCredentialUpdateEnabled(asyncCredentialUpdateEnabled) .profileFile(builder.profileFile) .profileName(builder.profileName) .build() };
詳細は認証情報プロバイダーチェーンを参照してください。
S3クライアントの作成
1.x では AmazonS3ClientBuilder
を使いましたが、2.x からは S3Client
からビルダーを生成してクライアントを構築します。
S3Client s3 = S3Client.builder() .region(Region.AP_NORTHEAST_1) .credentialsProvider(credentialsProvider) .build();
クライアントの設定は、1.x では ClientConfiguration
で行っていましたが、2.x からはそれぞれの用途別に設定が分割されています。例えば以下のような Configuration があります。
httpClientBuilder
(ApacheHttpClient
/NettyNioAsyncHttpClient
)ProxyConfiguration
ClientOverrideConfiguration
RetryPolicy
ClientAsyncConfiguration
それぞれの設定を以下のように個別に適用します。
ProxyConfiguration.Builder proxyConfig = ProxyConfiguration.builder(); ApacheHttpClient.Builder httpClientBuilder = ApacheHttpClient.builder() .proxyConfiguration(proxyConfig.build()); ClientOverrideConfiguration.Builder overrideConfig = ClientOverrideConfiguration.builder(); S3Client s3 = S3Client.builder() .httpClientBuilder(httpClientBuilder) .overrideConfiguration(overrideConfig.build()) .build();
httpClientBuilder()
では、HTTPクライアントを指定します。現在4種のHTTPクライアントが提供されており、指定しない場合は ApacheHttpClient
が使われます。
ApacheHttpClient
デフォルトの同期HTTPクライアントUrlConnectionHttpClient
軽量な同期HTTPクライアントNettyNioAsyncHttpClient
非同期クライアント(非同期のデフォルト)AwsCrtAsyncHttpClient
起動が早い非同期クライアント(AWS Lambda ではこちらを利用)
オブジェクトのアップロード
PutObjectRequest
を使い以下のようになります。
PutObjectRequest putObj = PutObjectRequest.builder()
.bucket(bucketName)
.key(objectKey)
.build();
s3.putObject(putObl, RequestBody.fromFile(new File(objectPath)));
ラムダ形式で以下のように書くこともできます。
s3Client.putObject(req -> req.bucket(bucketName).key(objectKey), RequestBody.fromBytes(bytes));
メタデータを付与する場合は以下のようになります。
var metadata = Map.of("x-amz-meta-myVal", "test"); s3Client.putObject(req -> req.bucket(bucketName).key(objectKey).metadata(metadata), RequestBody.fromBytes(bytes));
オブジェクトの取得
GetObjectRequest
を使い以下のようになります。
GetObjectRequest req = GetObjectRequest.builder()
.bucket(bucketName)
.key(keyName)
.build();
ResponseBytes<GetObjectResponse> res = s3.getObjectAsBytes(req);
byte[] data = objectBytes.asByteArray();
ラムダ形式で以下のように書くこともできます。
byte[] data = s3.getObjectAsBytes(req ->
req.bucket(bucketName).key(keyName)).asByteArray();
オブジェクトの一覧
ListObjectsRequest
を使い以下のようになります。
ListObjectsRequest listObjects = ListObjectsRequest.builder() .bucket(bucketName) .build(); ListObjectsResponse res = s3.listObjects(listObjects); List<S3Object> objects = res.contents(); for (S3Object myValue : objects) { // ... }
listObjectsV2Paginator()
でページ毎に処理できます。
s3.listObjectsV2Paginator(req -> req.bucket(bucketName)).stream() .flatMap(r -> r.contents().stream()) .forEach(c -> System.out.println(" Key: " + c.key() + " size = " + c.size()));
デフォルトでは1ページは1,000件となっています( maxKeys()
で変更可)。
オブジェクトの削除
DeleteObjectRequest
を使い以下のようになります。
DeleteObjectRequest req = DeleteObjectRequest.builder() .bucket(bucketName) .key(keyName) .build(); s3.deleteObject(req);
ラムダ形式で以下のように書くこともできます。
s3Client.deleteObject(req -> req.bucket(bucketName).key(keyName));
S3 Transfer Manager
大容量・大量のファイルの転送を行う場合は、S3 Transfer Manager を使うことでパフォーマンスを改善できます。
S3 Transfer Manager を使うには、以下の依存を追加します。
implementation("software.amazon.awssdk:s3-transfer-manager:2.20.+") implementation("software.amazon.awssdk.crt:aws-crt:0.27.+")
S3TransferManager
は以下のようにしてインスタンスを生成します。
S3AsyncClient s3AsyncClient = S3AsyncClient.crtBuilder() .credentialsProvider(DefaultCredentialsProvider.create()) .region(Region.AP_NORTHEAST_1) .targetThroughputInGbps(20.0) .minimumPartSizeInBytes(8 * MB) .build(); S3TransferManager tm = S3TransferManager.builder() .s3AsyncClient(s3AsyncClient) .build();
S3TransferManager
では、転送の進行状況をリアルタイムで監視したり、転送を一時停止して後で再開するなど、柔軟な転送処理が実現できます。
S3 Transfer Manager によるアップロード
S3 Transfer Manager でファイルをアップロードするには UploadFileRequest
を使います。
UploadFileRequest uploadFileRequest = UploadFileRequest.builder()
.putObjectRequest(req -> req.bucket(bucketName).key(keyName))
.addTransferListener(LoggingTransferListener.create())
.source(Paths.get("etc.txt"))
.build();
FileUpload upload = transferManager.uploadFile(uploadFileRequest);
upload.completionFuture().join();
S3 Transfer Manager によるダウンロード
S3 Transfer Manager でファイルをダウンロードするには DownloadFileRequest
を使います。
DownloadFileRequest downloadFileRequest = DownloadFileRequest.builder()
.getObjectRequest(req ->
req.bucket(bucketName).key(keyName))
.destination(Paths.get("etc.txt"))
.addTransferListener(LoggingTransferListener.create())
.build();
FileDownload download = transferManager.downloadFile(downloadFileRequest);
download.completionFuture().join();
S3 Transfer Manager によるディレクトリアップロード
ディレクトリ内のファイルをまるごとアップロードするには UploadDirectoryRequest
を使います。
S3TransferManager tm = S3TransferManager.create();
DirectoryUpload directoryUpload = tm.uploadDirectory(
UploadDirectoryRequest.builder()
.source(Paths.get("source/directory"))
.bucket(bucketName)
.build());
CompletedDirectoryUpload completedDirectoryUpload = directoryUpload.completionFuture().join();
completedDirectoryUpload.failedTransfers().forEach(System.out::println);
S3 Transfer Manager による全オブジェクトダウンロード
バケット内のオブジェクトを一括してディレクトリにダウンロードするには DownloadDirectoryRequest
を使います。
DirectoryDownload directoryDownload = tm.downloadDirectory(
DownloadDirectoryRequest.builder()
.destination(Paths.get("destination/directory"))
.bucket(bucketName)
.build());
CompletedDirectoryDownload completedDirectoryDownload = directoryDownload.completionFuture().join();
completedDirectoryDownload.failedTransfers().forEach(System.out::println);