Migrar o Gerenciador de Transferências da versão 1 para a versão 2 do AWS SDK para Java
Esse guia de migração aborda as principais diferenças entre o Gerenciador de Transferências v1 e o Gerenciador de Transferências v2 do S3, incluindo alterações no construtor, mapeamentos de métodos e exemplos de código para operações comuns. Depois de analisar essas diferenças, você pode migrar com êxito o código existente do Gerenciador de Transferências para aproveitar o desempenho aprimorado e as operações assíncronas na v2.
Sobre a ferramenta de migração do AWS SDK
O AWS SDK para Java fornece uma ferramenta de migração automatizada que pode migrar grande parte da API do Gerenciador de Transferências v1 para a v2. No entanto, a ferramenta de migração não é compatível com vários recursos do Gerenciador de Transferências v1. Nesses casos, você precisa migrar manualmente o código do Gerenciador de Transferências usando as orientações deste tópico.
Ao longo deste guia, o status da migração mostra se a ferramenta de migração pode migrar automaticamente um construtor, método ou recurso:
-
Compatível: a ferramenta de migração pode transformar automaticamente esse código
-
Incompatível: você precisa migrar o código manualmente
Mesmo para itens marcados com o status “Compatível”, revise os resultados da migração e faça um teste completo. A migração do Gerenciador de Transferências envolve mudanças de arquitetura significativas de operações síncronas para assíncronas.
Visão geral
O Gerenciador de Transferências do S3 v2 introduz mudanças significativas na API do Gerenciador de Transferências. O Gerenciador de Transferências do S3 v2 é baseado em operações assíncronas e oferece melhor desempenho, especialmente quando você usa o cliente Amazon S3 baseado no AWS CRT.
Principais diferenças
-
Pacote:
com.amazonaws.services.s3.transfer→software.amazon.awssdk.transfer.s3 -
Nome da classe:
TransferManager→S3TransferManager -
Dependência do cliente: cliente síncrono do Amazon S3 → cliente assíncrono do Amazon S3 (
S3AsyncClient) -
Arquitetura: operações síncronas → operações assíncronas com
CompletableFuture -
Desempenho: aprimorado com o suporte ao cliente baseado no AWS
Alterações de alto nível
| Aspecto | V1 | V2 |
|---|---|---|
| Dependência do Maven | aws-java-sdk-s3 |
s3-transfer-manager |
| Pacote | com.amazonaws.services.s3.transfer |
software.amazon.awssdk.transfer.s3 |
| Classe principal | TransferManager |
S3TransferManager |
| Cliente do Amazon S3 | AmazonS3 (síncrono) |
S3AsyncClient (assíncrono) |
| Tipos de retorno | Operações de bloqueio | CompletableFuture<T> |
Dependências do Maven
| V1 | V2 |
|---|---|
|
|
1 Versão mais recente
Migração do construtor do cliente
Construtores compatíveis (migração automática)
| Construtor V1 | V2 equivalente | Status da migração |
|---|---|---|
new TransferManager() |
S3TransferManager.create() |
Compatível |
TransferManagerBuilder.
defaultTransferManager() |
S3TransferManager.create() |
Compatível |
TransferManagerBuilder.
standard().build() |
S3TransferManager.builder().build() |
Compatível |
new TransferManager(AWSCredentials) |
S3TransferManager.builder()
.s3Client(S3AsyncClient.builder()
.credentialsProvider(...).build())
.build() |
Compatível |
new TransferManager(
AWSCredentialsProvider) |
S3TransferManager.builder()
.s3Client(S3AsyncClient.builder()
.credentialsProvider(...).build())
.build() |
Compatível |
Construtores incompatíveis (migração manual obrigatória)
| Construtor V1 | V2 equivalente | Notas de migração |
|---|---|---|
new TransferManager(AmazonS3) |
Migração manual obrigatória | Criar um S3AsyncClient separadamente |
new TransferManager(AmazonS3,
ExecutorService) |
Migração manual obrigatória | Criar um S3AsyncClient e configurar um executor |
new TransferManager(AmazonS3,
ExecutorService, boolean) |
Migração manual obrigatória | Parâmetro shutDownThreadPools incompatível |
Exemplos de migração manual
Código da V1:
AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();
TransferManager transferManager = new TransferManager(s3Client);
Código da V2:
// Create an `S3AsyncClient` with similar configuration
S3AsyncClient s3AsyncClient = S3AsyncClient.builder()
.credentialsProvider(DefaultCredentialsProvider.create())
.build();
// Provide the configured `S3AsyncClient` to the S3 transfer manager builder.
S3TransferManager transferManager = S3TransferManager.builder()
.s3Client(s3AsyncClient)
.build();
Migração do método do cliente
Atualmente, a ferramenta de migração é compatível com os métodos básicos copy, download, upload, uploadDirectory, downloadDirectory, resumeDownload e resumeUpload.
Métodos de transferência principais
| Método da V1 | Método da V2 | Alteração do tipo de retorno | Status da migração |
|---|---|---|---|
upload(String, String, File) |
uploadFile(UploadFileRequest) |
Upload → FileUpload |
Compatível |
upload(PutObjectRequest) |
upload(UploadRequest) |
Upload → Upload |
Compatível |
download(String, String, File) |
downloadFile(DownloadFileRequest) |
Download → FileDownload |
Compatível |
download(GetObjectRequest, File) |
downloadFile(DownloadFileRequest) |
Download → FileDownload |
Compatível |
copy(String, String, String, String) |
copy(CopyRequest) |
Copy → Copy |
Compatível |
copy(CopyObjectRequest) |
copy(CopyRequest) |
Copy → Copy |
Compatível |
uploadDirectory(String, String,
File, boolean) |
uploadDirectory(
UploadDirectoryRequest) |
MultipleFileUpload →
DirectoryUpload |
Compatível |
downloadDirectory(String, String, File) |
downloadDirectory(
DownloadDirectoryRequest) |
MultipleFileDownload →
DirectoryDownload |
Compatível |
Métodos de transferência com retomada
| Método da V1 | Método da V2 | Status da migração |
|---|---|---|
resumeUpload(PersistableUpload) |
resumeUploadFile(ResumableFileUpload) |
Compatível |
resumeDownload(PersistableDownload) |
resumeDownloadFile(ResumableFileDownload) |
Compatível |
Métodos do ciclo de vida
| Método da V1 | Método da V2 | Status da migração |
|---|---|---|
shutdownNow() |
close() |
Compatível |
shutdownNow(boolean) |
Ajustar manualmente o código usando o método close() |
Sem suporte |
Métodos de cliente V1 incompatíveis
| Método da V1 | V2 alternativa | Observações |
|---|---|---|
abortMultipartUploads(String, Date) |
Use o cliente de nível baixo do Amazon S3 | Sem suporte |
getAmazonS3Client() |
Salvar uma referência separadamente | Incompatível; não há getter na v2 |
getConfiguration() |
Salvar uma referência separadamente | Incompatível; não há getter na v2 |
uploadFileList(...) |
Fazer várias chamadas uploadFile() |
Sem suporte |
Métodos copy com um parâmetro TransferStateChangeListener |
Use TransferListener |
Consulte um exemplo de migração manual |
Métodos download com um parâmetro S3ProgressListener |
Use TransferListener |
Consulte um exemplo de migração manual |
|
Métodos |
Consulte um exemplo de migração manual | |
Método upload com um parâmetro ObjectMetadataProvider |
Definir metadados na solicitação | Consulte um exemplo de migração manual |
Métodos uploadDirectory com um parâmetro *Provider |
Definir tags na solicitação | Consulte um exemplo de migração manual |
Métodos copy com um parâmetro TransferStateChangeListener
-
copy(CopyObjectRequest copyObjectRequest, AmazonS3 srcS3, TransferStateChangeListener stateChangeListener) -
copy(CopyObjectRequest copyObjectRequest, TransferStateChangeListener stateChangeListener)
// V1 ---------------------------------------------------------------------------------------------- // Initialize source S3 client AmazonS3 s3client = AmazonS3ClientBuilder.standard() .withRegion("us-west-2") .build(); // Initialize Transfer Manager TransferManager tm = TransferManagerBuilder.standard() .withS3Client(srcS3) .build(); CopyObjectRequest copyObjectRequest = new CopyObjectRequest( "amzn-s3-demo-source-bucket", "source-key", "amzn-s3-demo-destination-bucket", "destination-key" ); TransferStateChangeListener stateChangeListener = new TransferStateChangeListener() { @Override public void transferStateChanged(Transfer transfer, TransferState state) { //Implementation of the TransferStateChangeListener } }; Copy copy = tm.copy(copyObjectRequest, srcS3, stateChangeListener); // V2 ---------------------------------------------------------------------------------------------- S3AsyncClient s3AsyncClient = S3AsyncClient.builder() .region(Region.US_WEST_2) .build(); S3TransferManager transferManager = S3TransferManager.builder() .s3Client(s3AsyncClient) .build(); // Create transfer listener (equivalent to TransferStateChangeListener in v1) TransferListener transferListener = new TransferListener() { @Override public void transferInitiated(Context.TransferInitiated context) { //Implementation System.out.println("Transfer initiated"); } @Override public void bytesTransferred(Context.BytesTransferred context) { //Implementation System.out.println("Bytes transferred"); } @Override public void transferComplete(Context.TransferComplete context) { //Implementation System.out.println("Transfer completed!"); } @Override public void transferFailed(Context.TransferFailed context) { //Implementation System.out.println("Transfer failed"); } }; CopyRequest copyRequest = CopyRequest.builder() .copyObjectRequest(req -> req .sourceBucket("amzn-s3-demo-source-bucket") .sourceKey("source-key") .destinationBucket("amzn-s3-demo-destination-bucket") .destinationKey("destination-key") ) .addTransferListener(transferListener) // Configure the transferListener into the request .build(); Copy copy = transferManager.copy(copyRequest);
Métodos download com um parâmetro S3ProgressListener
-
download(GetObjectRequest getObjectRequest, File file, S3ProgressListener progressListener) -
download(GetObjectRequest getObjectRequest, File file, S3ProgressListener progressListener, long timeoutMillis) -
download(GetObjectRequest getObjectRequest, File file, S3ProgressListener progressListener, long timeoutMillis, boolean resumeOnRetry)
// V1 ---------------------------------------------------------------------------------------------- S3ProgressListener progressListener = new S3ProgressListener() { @Override public void progressChanged(com.amazonaws.event.ProgressEvent progressEvent) { long bytes = progressEvent.getBytesTransferred(); ProgressEventType eventType = progressEvent.getEventType(); // Use bytes and eventType as needed } @Override public void onPersistableTransfer(PersistableTransfer persistableTransfer) { } }; Download download1 = tm.download(getObjectRequest, file, progressListener); Download download2 = tm.download(getObjectRequest, file, progressListener, timeoutMillis) Download download3 = tm.download(getObjectRequest, file, progressListener, timeoutMillis, true) // V2 ---------------------------------------------------------------------------------------------- TransferListener transferListener = new TransferListener() { @Override public void transferInitiated(Context.InitializedContext context) { // Equivalent to ProgressEventType.TRANSFER_STARTED_EVENT System.out.println("Transfer initiated"); } @Override public void bytesTransferred(Context.BytesTransferred context) { // Equivalent to ProgressEventType.REQUEST_BYTE_TRANSFER_EVENT long bytes = context.bytesTransferred(); System.out.println("Bytes transferred: " + bytes); } @Override public void transferComplete(Context.TransferComplete context) { // Equivalent to ProgressEventType.TRANSFER_COMPLETED_EVENT System.out.println("Transfer completed"); } @Override public void transferFailed(Context.TransferFailed context) { // Equivalent to ProgressEventType.TRANSFER_FAILED_EVENT System.out.println("Transfer failed: " + context.exception().getMessage()); } }; DownloadFileRequest downloadFileRequest = DownloadFileRequest.builder() .getObjectRequest(getObjectRequest) .destination(file.toPath()) .addTransferListener(transferListener) .build(); // For download1 FileDownload download = transferManager.downloadFile(downloadFileRequest); // For download2 CompletedFileDownload completedFileDownload = download.completionFuture() .get(timeoutMillis, TimeUnit.MILLISECONDS); // For download3, the v2 SDK does not have a direct equiavalent to the `resumeOnRetry` method of v1. // If a download is interrupted, you need to start a new download request.
Métodos downloadDirectory com quatro ou mais parâmetros
-
downloadDirectory(String bucketName, String keyPrefix, File destinationDirectory, boolean resumeOnRetry) -
downloadDirectory(String bucketName, String keyPrefix, File destinationDirectory, boolean resumeOnRetry, KeyFilter filter) -
downloadDirectory(String bucketName, String keyPrefix, File destinationDirectory, KeyFilter filter)
// V1 ---------------------------------------------------------------------------------------------- KeyFilter filter = new KeyFilter() { @Override public boolean shouldInclude(S3ObjectSummary objectSummary) { //Filter implementation } }; MultipleFileDownload multipleFileDownload = tm.downloadDirectory(bucketName, keyPrefix, destinationDirectory, filter); // V2 ---------------------------------------------------------------------------------------------- // The v2 SDK does not have a direct equiavalent to the `resumeOnRetry` method of v1. // If a download is interrupted, you need to start a new download request. DownloadFilter filter = new DownloadFilter() { @Override public boolean test(S3Object s3Object) { // Filter implementation. } }; DownloadDirectoryRequest downloadDirectoryRequest = DownloadDirectoryRequest.builder() .bucket(bucketName) .filter(filter) .listObjectsV2RequestTransformer(builder -> builder.prefix(keyPrefix)) .destination(destinationDirectory.toPath()) .build(); DirectoryDownload directoryDownload = transferManager.downloadDirectory(downloadDirectoryRequest);
Método upload com um parâmetro ObjectMetadata
-
upload(String bucketName, String key, InputStream input, ObjectMetadata objectMetadata)
// V1 ----------------------------------------------------------------------------------------------ObjectMetadata metadata = new ObjectMetadata(); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentType("text/plain"); // System-defined metadata metadata.setContentLength(22L); // System-defined metadata metadata.addUserMetadata("myKey", "myValue"); // User-defined metadata PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream, metadata); Upload upload = transferManager.upload("amzn-s3-demo-bucket", "my-key", inputStream, metadata); // V2 ---------------------------------------------------------------------------------------------- /* When you use an InputStream to upload in V2, you should specify the content length and use `RequestBody.fromInputStream()`. If you don't provide the content length, the entire stream will be buffered in memory. If you can't determine the content length, we recommend using the CRT-based S3 client. */ Map<String, String> userMetadata = new HashMap<>(); userMetadata.put("x-amz-meta-myKey", "myValue"); PutObjectRequest putObjectRequest = PutObjectRequest.builder() .bucket("amzn-s3-demo-bucket1") .key("k") .contentType("text/plain") //System-defined metadata usually has separate methods in the builder. .contentLength(22L) .metadata(userMetadata) //metadata() is only for user-defined metadata. .build(); UploadRequest uploadRequest = UploadRequest.builder() .putObjectRequest(putObjectRequest) .requestBody(AsyncRequestBody.fromInputStream(stream, 22L, executor)) .build(); transferManager.upload(uploadRequest).completionFuture().join();
uploadDirectory com parâmetro ObjectMetadataProvider
-
uploadDirectory(String bucketName, String virtualDirectoryKeyPrefix, File directory, boolean includeSubdirectories, ObjectMetadataProvider metadataProvider) -
uploadDirectory(String bucketName, String virtualDirectoryKeyPrefix, File directory, boolean includeSubdirectories, ObjectMetadataProvider metadataProvider, ObjectTaggingProvider taggingProvider) -
uploadDirectory(String bucketName, String virtualDirectoryKeyPrefix, File directory, boolean includeSubdirectories, ObjectMetadataProvider metadataProvider, ObjectTaggingProvider taggingProvider, ObjectCannedAclProvider cannedAclProvider)
// V1 ---------------------------------------------------------------------------------------------- tm.uploadDirectory(bucketName, virtualDirectoryKeyPrefix, directory, includeSubdirectories, metadataProvider) tm.uploadDirectory(bucketName, virtualDirectoryKeyPrefix, directory, includeSubdirectories, metadataProvider, taggingProvider) tm.uploadDirectory(bucketName, virtualDirectoryKeyPrefix, directory, includeSubdirectories, metadataProvider, taggingProvider, cannedAclProvider) // V2 ---------------------------------------------------------------------------------------------- UploadDirectoryRequest request = UploadDirectoryRequest.builder() .bucket(bucketName) .s3Prefix(virtualDirectoryKeyPrefix) .source(directory.toPath()) .maxDepth(includeSubdirectories ? Integer.MAX_VALUE : 1) .uploadFileRequestTransformer(builder -> { // 1.Replace `ObjectMetadataProvider`, `ObjectTaggingProvider`, and `ObjectCannedAclProvider` with an // `UploadFileRequestTransformer` that can combine the functionality of all three *Provider implementations. // 2. Convert your v1 `ObjectMetadata` to v2 `PutObjectRequest` parameters. // 3. Convert your v1 `ObjectTagging` to v2 `Tagging`. // 4. Convert your v1 `CannedAccessControlList` to v2 `ObjectCannedACL`. }) .build(); DirectoryUpload directoryUpload = transferManager.uploadDirectory(request);
Migração de objetos de modelo
No AWS SDK for Java 2.x, muitos dos objetos do modelo TransferManager foram redefinidos e vários métodos getter e setter disponíveis nos objetos do modelo da v1 não são mais compatíveis.
Na v2, você pode usar a classe CompletableFuture<T> para realizar ações quando a transferência for concluída, seja com êxito ou com uma exceção. Você pode usar o método join() para aguardar a conclusão, se necessário.
Objetos de transferência principal
| Classe V1 | Classe V2 | Status da migração |
|---|---|---|
TransferManager |
S3TransferManager |
Compatível |
TransferManagerBuilder |
S3TransferManager.Builder |
Compatível |
Transfer |
Transfer |
Compatível |
AbortableTransfer |
Transfer |
Compatível (sem classe separada) |
Copy |
Copy |
Compatível |
Download |
FileDownload |
Compatível |
Upload |
Upload / FileUpload |
Compatível |
MultipleFileDownload |
DirectoryDownload |
Compatível |
MultipleFileUpload |
DirectoryUpload |
Compatível |
Objetos de persistência
| Classe V1 | Classe V2 | Status da migração |
|---|---|---|
PersistableDownload |
ResumableFileDownload |
Compatível |
PersistableUpload |
ResumableFileUpload |
Compatível |
PersistableTransfer |
ResumableTransfer |
Compatível |
PauseResult<T> |
Objeto com retomada direta | Sem suporte |
Objetos de resultado
| Classe V1 | Classe V2 | Status da migração |
|---|---|---|
CopyResult |
CompletedCopy |
Compatível |
UploadResult |
CompletedUpload |
Compatível |
Objetos de configuração
| Classe V1 | Classe V2 | Status da migração |
|---|---|---|
TransferManagerConfiguration |
MultipartConfiguration (no cliente do Amazon S3) |
Compatível |
TransferProgress |
TransferProgress + TransferProgressSnapshot |
Compatível |
KeyFilter |
DownloadFilter |
Compatível |
Objetos não compatíveis
| Classe V1 | V2 alternativa | Status da migração |
|---|---|---|
PauseStatus |
Não compatível | Sem suporte |
UploadContext |
Não compatível | Sem suporte |
ObjectCannedAclProvider |
PutObjectRequest.builder().acl() |
Sem suporte |
ObjectMetadataProvider |
PutObjectRequest.builder().metadata() |
Sem suporte |
ObjectTaggingProvider |
PutObjectRequest.builder().tagging() |
Sem suporte |
PresignedUrlDownload |
Não compatível | Sem suporte |
Migração de configuração de TransferManagerBuilder
Alterações de configuração
As alterações de configuração que você precisa definir para o Gerenciador de Transferências v2 dependem do cliente do S3 que você usa. Você pode escolher entre o cliente do S3 baseado no AWS CRT ou o cliente assíncrono do S3 padrão baseado em Java. Consulte informações sobre as diferenças no tópico Clientes do S3 no AWS SDK for Java 2.x.
Alteração de comportamento
Operações assíncronas
V1 (bloqueio):
Upload upload = transferManager.upload("amzn-s3-demo-bucket", "key", file);
upload.waitForCompletion(); // Blocks until complete
V2 (assíncrono):
FileUpload upload = transferManager.uploadFile(UploadFileRequest.builder()
.putObjectRequest(PutObjectRequest.builder()
.bucket("amzn-s3-demo-bucket")
.key("key")
.build())
.source(file)
.build());
CompletedFileUpload result = upload.completionFuture().join(); // Blocks until complete
// Or handle asynchronously:
upload.completionFuture().thenAccept(result -> {
System.out.println("Upload completed: " + result.response().eTag());
});
Tratamento de erros
V1: as transferências de diretórios falham completamente se alguma subsolicitação falha.
V2: as transferências de diretórios são concluídas com êxito mesmo se algumas subsolicitações falham. Verifique se há erros de forma explícita:
DirectoryUpload directoryUpload = transferManager.uploadDirectory(request);
CompletedDirectoryUpload result = directoryUpload.completionFuture().join();
// Check for failed transfers
if (!result.failedTransfers().isEmpty()) {
System.out.println("Some uploads failed:");
result.failedTransfers().forEach(failed ->
System.out.println("Failed: " + failed.exception().getMessage()));
}
Download paralelo por meio de buscas de intervalo de bytes
Quando o recurso de transferência paralela automática está ativado no SDK v2, o Gerenciador de Transferências do S3 usa buscas de intervalo de bytes para recuperar partes específicas do objeto em paralelo (download multipart). A forma como um objeto é baixado com a v2 não depende de como o objeto foi originalmente carregado. Todos os downloads podem se beneficiar da alta taxa de transferência e da simultaneidade.
Por outro lado, com o Gerenciador de Transferências v1, faz diferença como o objeto foi originalmente carregado. O Gerenciador de Transferências v1 recupera as partes do objeto da mesma forma que as partes foram carregadas. Se um objeto foi originalmente carregado como um único objeto, o Gerenciador de transferência v1 não é capaz de acelerar o processo de download usando subsolicitações.