Skip to content
Learni
Voir tous les tutoriels
Développement Cloud

Comment maîtriser l'AWS SDK for Java en 2026

Read in English

Introduction

L'AWS SDK for Java v2 représente l'évolution majeure pour les applications Java scalables en 2026. Contrairement à la v1 synchrone, la v2 met l'accent sur les clients asynchrones (Netty), la pagination native et les transactions cross-services, essentiels pour des microservices performants. Ce tutoriel avancé cible les développeurs seniors : nous couvrons la configuration Maven, les credentials sécurisés via STS, les uploads S3 multipart >5GB, les transactions DynamoDB atomiques, la pagination EC2 avec Paginators et la gestion d'erreurs retryable. Chaque exemple est un snippet complet, testable en <5min avec un compte AWS gratuit. À la fin, vous bookmarkederez ce guide pour vos déploiements prod. (132 mots)

Prérequis

  • Java 17+ (LTS recommandé pour GraalVM compatibilité)
  • Maven 3.9+ ou Gradle 8+
  • Compte AWS avec IAM user (clés API)
  • AWS CLI installé pour tester (aws configure)
  • IDE comme IntelliJ avec AWS Toolkit
  • Connaissances avancées en Java (CompletableFuture, Streams)

Configuration Maven (pom.xml)

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>aws-sdk-advanced</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <aws.sdk2.version>2.26.20</aws.sdk2.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>${aws.sdk2.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>dynamodb</artifactId>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>ec2</artifactId>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>sts</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>2.0.13</version>
        </dependency>
    </dependencies>
</project>

Ce pom.xml utilise le BOM pour gérer les versions SDK v2 cohérentes, évitant les conflits. Il inclut S3, DynamoDB, EC2 et STS pour assume-role. Compilez avec mvn compile ; piège : oubliez pas le BOM, sinon versions mismatch.

Gestion des credentials avancés

Pour la prod, évitez les clés hardcodées. Utilisez ~/.aws/credentials avec MFA ou assume-role via STS pour des sessions temporaires (15min-12h). La chaîne de providers SDK priorise : env vars > shared creds > IAM roles (EC2/Lambda).

Client STS AssumeRole asynchrone

StsAssumeRole.java
package com.example;

import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;

import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sts.StsAsyncClient;
import software.amazon.awssdk.services.sts.model.AssumeRoleRequest;
import software.amazon.awssdk.services.sts.model.AssumeRoleResponse;
import software.amazon.awssdk.services.sts.model.Credentials;

import java.time.Duration;

public class StsAssumeRole {
    public static void main(String[] args) {
        StsAsyncClient stsClient = StsAsyncClient.builder()
                .region(Region.EU_WEST_1)
                .credentialsProvider(ProfileCredentialsProvider.create("dev-profile"))
                .build();

        AssumeRoleRequest request = AssumeRoleRequest.builder()
                .roleArn("arn:aws:iam::123456789012:role/MyCrossAccountRole")
                .roleSessionName("java-sdk-session")
                .durationSeconds(3600)
                .build();

        stsClient.assumeRole(request).whenComplete((response, throwable) -> {
            if (throwable != null) {
                throwable.printStackTrace();
                return;
            }
            Credentials creds = response.credentials();
            System.out.println("AccessKey: " + creds.accessKeyId());
            System.out.println("Expires: " + creds.expirationTime());
        }).join();

        stsClient.close();
    }
}

Ce code assume un rôle cross-account de façon asynchrone avec CompletableFuture. Utilisez ces creds temporaires pour d'autres clients. Piège : région STS doit matcher ; testez avec aws sts assume-role d'abord.

S3 : Upload multipart avancé

Analogie : Comme diviser un camion en remorques pour une autoroute saturée. Pour fichiers >5GB, multipart est obligatoire (100 parts max, 5MB-5GB/part). Nous créons un upload complet avec metadata et tagging.

S3 Multipart Upload complet

S3MultipartUpload.java
package com.example;

import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class S3MultipartUpload {
    public static void main(String[] args) throws IOException {
        S3Client s3 = S3Client.builder().region(Region.EU_WEST_1).build();
        String bucket = "my-advanced-bucket";
        String key = "large-file.zip";
        File file = new File("path/to/largefile.zip"); // >5GB

        // Create multipart upload
        CreateMultipartUploadResponse createRes = s3.createMultipartUpload(CreateMultipartUploadRequest.builder()
                .bucket(bucket)
                .key(key)
                .metadata(m -> m.put("app", "java-sdk-v2"))
                .tagging("env=prod&priority=high")
                .build());
        String uploadId = createRes.uploadId();

        List<CompletedPart> parts = new ArrayList<>();
        int partNumber = 1;
        long fileSize = file.length();
        long partSize = 5 * 1024 * 1024; // 5MB

        byte[] fileContent = Files.readAllBytes(file.toPath());
        for (long pos = 0; pos < fileSize; pos += partSize) {
            long size = Math.min(partSize, fileSize - pos);
            UploadPartResponse partRes = s3.uploadPart(UploadPartRequest.builder()
                    .bucket(bucket)
                    .key(key)
                    .uploadId(uploadId)
                    .partNumber(partNumber)
                    .contentLength(size)
                    .build(), RequestBody.fromBytes(fileContent, (int)pos, (int)size));
            parts.add(CompletedPart.builder().eTag(partRes.eTag()).partNumber(partNumber).build());
            partNumber++;
        }

        // Complete
        s3.completeMultipartUpload(CompletedMultipartUploadRequest.builder()
                .bucket(bucket)
                .key(key)
                .uploadId(uploadId)
                .parts(parts)
                .build());

        s3.close();
        System.out.println("Upload complet!");
    }
}

Code synchrone pour simplicité, mais passez à S3AsyncClient pour prod. Gère metadata/tags auto-appliqués. Piège : sortez parts par partNumber ascendant ; abortez avec AbortMultipartUpload si échec.

DynamoDB : Transactions atomiques

Les TransactWriteItems garantissent ACID cross-tables (100 ops max). Idéal pour e-commerce (débit stock + commande). Utilisez conditions pour éviter race conditions.

DynamoDB TransactWriteItems

DynamoDBTransactions.java
package com.example;

import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.*;

import java.util.Arrays;

public class DynamoDBTransactions {
    public static void main(String[] args) {
        DynamoDbClient dynamoDb = DynamoDbClient.builder().region(Region.EU_WEST_1).build();
        String tableOrders = "Orders";
        String tableInventory = "Inventory";

        TransactWriteItem orderItem = TransactWriteItem.builder()
                .put(Put.builder().tableName(tableOrders)
                        .item(m -> m.attribute("orderId", AttributeValue.builder().s("ORD-123").build())
                                .attribute("productId", AttributeValue.builder().s("PROD-456").build())
                                .attribute("quantity", AttributeValue.builder().n("2").build()))
                        .build())
                .build();

        TransactWriteItem inventoryItem = TransactWriteItem.builder()
                .update(Update.builder().tableName(tableInventory)
                        .key(k -> k.attribute("productId", AttributeValue.builder().s("PROD-456").build()))
                        .updateExpression("ADD quantity :dec")
                        .expressionAttributeValues(m -> m.put(":dec", AttributeValue.builder().n("2").build()))
                        .conditionExpression("quantity >= :dec")
                        .build())
                .build();

        try {
            dynamoDb.transactWriteItems(TransactWriteItemsRequest.builder()
                    .transactItems(Arrays.asList(orderItem, inventoryItem))
                    .build());
            System.out.println("Transaction réussie!");
        } catch (TransactionCanceledException e) {
            System.out.println("Annulée: " + e.cancellationReasons());
        }

        dynamoDb.close();
    }
}

Transaction atomique : commande + update stock avec condition. Si stock insuffisant, tout rollback. Piège : limitez à 4MB total ; utilisez Batch pour non-atomique.

Pagination EC2 avec Paginators

Avancé : Pour >1000 instances, utilisez paginator() pour itérer sans NextToken manuelle. Flux réactif compatible avec Reactor/WebFlux.

EC2 Pagination avancée

EC2Pagination.java
package com.example;

import software.amazon.awssdk.services.ec2.Ec2Client;
import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest;
import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse;
import software.amazon.awssdk.services.ec2.paginators.DescribeInstancesPublisher;

import java.util.concurrent.CompletableFuture;

public class EC2Pagination {
    public static void main(String[] args) {
        Ec2Client ec2 = Ec2Client.builder().region(Region.EU_WEST_1).build();

        DescribeInstancesPublisher publisher = ec2.paginator(DescribeInstancesRequest.builder().maxResults(50).build());

        CompletableFuture<Void> future = publisher.subscribe(res -> {
            res.reservations().forEach(reservation ->
                    reservation.instances().forEach(instance ->
                            System.out.println("Instance: " + instance.instanceId())));
        });

        future.join();
        ec2.close();
    }
}

Publisher itère automatiquement sur pages (Publisher/Subscriber pattern). Async par défaut. Piège : maxResults trop haut throttle ; filirez avec .filter() sur Flux si Spring.

Bonnes pratiques

  • Clients singleton : Réutilisez un client par région/app via builder.cache()
  • Async partout : Préférez AsyncClient pour I/O non-bloquant (>10x perf)
  • Retry policy : Configurez SdkDefaultClientExceptionRetryClassifier pour 503/429
  • Logging structuré : Activez AWS_XRAY pour traces distribuées
  • Régions multi : Utilisez Region.of() dynamique par service

Erreurs courantes à éviter

  • Credentials chain incomplète : Vérifiez AWS_PROFILE et ~/.aws/config ; testez avec aws sts get-caller-identity
  • Pagination manuelle : Oublie NextToken → résultats tronqués ; toujours paginator()
  • Multipart sans complete : Coûts storage orphelins ; wrappez en try-finally
  • ConditionCheck fail : TransactionCanceledException sans log reasons()

Pour aller plus loin