Gunakan pemrograman asinkron - AWS SDK for Java 2.x

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Gunakan pemrograman asinkron

AWS SDK for Java 2.x Fitur klien asinkron dengan dukungan I/O non-pemblokiran yang menerapkan konkurensi tinggi di beberapa utas. Namun, total I/O non-pemblokiran tidak dijamin. Klien asinkron dapat melakukan pemblokiran panggilan dalam beberapa kasus seperti pengambilan kredensyal, penandatanganan permintaan menggunakan AWS Sigv4 (SigV4), atau penemuan titik akhir.

Metode sinkron memblokir eksekusi thread Anda hingga klien menerima respons dari layanan. Metode asinkron segera kembali, memberikan kontrol kembali ke utas panggilan tanpa menunggu respons.

Karena metode asinkron kembali sebelum respons tersedia, Anda memerlukan cara untuk mendapatkan respons saat sudah siap. Metode untuk klien asinkron di 2.x dari CompletableFuture objek AWS SDK for Java kembali yang memungkinkan Anda mengakses respons saat sudah siap.

Gunakan klien asinkron APIs

Tanda tangan metode klien asinkron sama dengan rekan sinkron mereka, tetapi metode asinkron mengembalikan CompletableFutureobjek yang berisi hasil operasi asinkron di masa depan. Jika kesalahan dilemparkan saat metode asinkron SDK dijalankan, kesalahan dilemparkan sebagai. CompletionException

Salah satu pendekatan yang dapat Anda gunakan untuk mendapatkan hasilnya adalah dengan menghubungkan whenComplete() metode ke yang CompletableFuture dikembalikan oleh pemanggilan metode SDK. whenComplete()Metode menerima hasil atau objek Throwable dari tipe CompletionException tergantung pada bagaimana panggilan asinkron selesai. Anda memberikan tindakan whenComplete() untuk memproses atau memeriksa hasil sebelum dikembalikan ke kode panggilan.

Jika Anda ingin mengembalikan sesuatu selain objek yang dikembalikan oleh metode SDK, gunakan handle() metode sebagai gantinya. handle()Metode ini mengambil parameter yang sama sepertiwhenComplete(), tetapi Anda dapat memproses hasilnya dan mengembalikan objek.

Untuk menunggu rantai asinkron selesai dan mengambil hasil penyelesaian, Anda dapat memanggil metode. join() Jika Throwable objek tidak ditangani dalam rantai, join() metode melempar tanda centang CompletionException yang membungkus pengecualian asli. Anda mengakses pengecualian asli denganCompletionException#getCause(). Anda juga dapat memanggil CompletableFuture#get() metode untuk mendapatkan hasil penyelesaian. get()Metode ini, bagaimanapun, dapat membuang pengecualian yang diperiksa.

Contoh berikut menunjukkan dua variasi bagaimana Anda dapat bekerja dengan listTables() metode klien asinkron DynamoDB. Tindakan diteruskan untuk whenComplete() hanya mencatat respons yang berhasil, sedangkan handle() versi mengekstrak daftar nama tabel dan mengembalikan daftar. Dalam kedua kasus jika kesalahan dihasilkan dalam rantai asinkron, kesalahan dilemparkan kembali sehingga kode klien memiliki kesempatan untuk menanganinya.

Impor

import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.model.ListTablesRequest; import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse; import java.util.List; import java.util.concurrent.CompletableFuture;

Kode

whenComplete() variation
public class DynamoDbAsyncListTables { public static void main(String[] args) { Region region = Region.US_EAST_1; DynamoDbAsyncClient dynamoDbAsyncClient = DynamoDbAsyncClient.builder().region(region).build(); try { ListTablesResponse listTablesResponse = listTablesWhenComplete(dynamoDbAsyncClient).join(); // The join() method may throw a CompletionException. if (listTablesResponse.hasTableNames()){ System.out.println("Table exist in this region: " + region.id()); } } catch (RuntimeException e) { // Handle as needed. Here we simply print out the class names. System.out.println(e.getClass()); // Prints 'class java.util.concurrent.CompletionException'. System.out.println(e.getCause().getClass()); // Prints 'class software.amazon.awssdk.services.dynamodb.model.DynamoDbException'. } } public static CompletableFuture<ListTablesResponse> listTablesWhenComplete(DynamoDbAsyncClient client) { return client.listTables(ListTablesRequest.builder().build()) .whenComplete((listTablesResponse, throwable) -> { if (listTablesResponse != null) { // Consume the response. System.out.println("The SDK's listTables method completed successfully."); } else { RuntimeException cause = (RuntimeException) throwable.getCause(); // If an error was thrown during the SDK's listTables method it is wrapped in a CompletionException. // The SDK throws only RuntimeExceptions, so this is a safe cast. System.out.println(cause.getMessage()); // Log error here, but rethrow so the calling code can handle as needed. throw cause; } }); }
handle() variation
public class DynamoDbAsyncListTables { public static void main(String[] args) { Region region = Region.US_EAST_1; DynamoDbAsyncClient dynamoDbAsyncClient = DynamoDbAsyncClient.builder().region(region).build(); try { List<String> tableNames = listTablesHandle(dynamoDbAsyncClient).join(); // The join() method may throw a CompletionException. tableNames.forEach(System.out::println); } catch (RuntimeException e) { // Handle as needed. Here we simply print out the class names. System.out.println(e.getClass()); // Prints 'class java.util.concurrent.CompletionException'. System.out.println(e.getCause().getClass()); // Prints 'class software.amazon.awssdk.services.dynamodb.model.DynamoDbException'. } } public static CompletableFuture<List<String>> listTablesHandle(DynamoDbAsyncClient client) { return client.listTables(ListTablesRequest.builder().build()) .handle((listTablesResponse, throwable) -> { if (listTablesResponse != null) { return listTablesResponse.tableNames(); // Return the list of table names. } else { RuntimeException cause = (RuntimeException) throwable.getCause(); // If an error was thrown during the SDK's listTables method it is wrapped in a CompletionException. // The SDK throws only RuntimeExceptions, so this is a safe cast. System.out.println(cause.getMessage()); // Log error here, but rethrow so the calling code can handle as needed. throw cause; } }); } }

Menangani streaming dalam metode asinkron

Untuk metode asinkron dengan konten streaming, Anda harus menyediakan AsyncRequestBodyuntuk menyediakan konten secara bertahap, atau AsyncResponseTransformeruntuk menerima dan memproses respons.

Contoh berikut mengunggah file ke Amazon S3 asinkron dengan menggunakan bentuk operasi asinkron. PutObject

Impor

import software.amazon.awssdk.core.async.AsyncRequestBody; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import software.amazon.awssdk.services.s3.model.PutObjectResponse; import java.nio.file.Paths; import java.util.concurrent.CompletableFuture;

Kode

/** * To run this AWS code example, ensure that you have setup your development environment, including your AWS credentials. * * For information, see this documentation topic: * * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html */ public class S3AsyncOps { public static void main(String[] args) { final String USAGE = "\n" + "Usage:\n" + " S3AsyncOps <bucketName> <key> <path>\n\n" + "Where:\n" + " bucketName - the name of the Amazon S3 bucket (for example, bucket1). \n\n" + " key - the name of the object (for example, book.pdf). \n" + " path - the local path to the file (for example, C:/AWS/book.pdf). \n" ; if (args.length != 3) { System.out.println(USAGE); System.exit(1); } String bucketName = args[0]; String key = args[1]; String path = args[2]; Region region = Region.US_WEST_2; S3AsyncClient client = S3AsyncClient.builder() .region(region) .build(); PutObjectRequest objectRequest = PutObjectRequest.builder() .bucket(bucketName) .key(key) .build(); // Put the object into the bucket CompletableFuture<PutObjectResponse> future = client.putObject(objectRequest, AsyncRequestBody.fromFile(Paths.get(path)) ); future.whenComplete((resp, err) -> { try { if (resp != null) { System.out.println("Object uploaded. Details: " + resp); } else { // Handle error err.printStackTrace(); } } finally { // Only close the client when you are completely done with it client.close(); } }); future.join(); } }

Contoh berikut mendapatkan file dari Amazon S3 dengan menggunakan bentuk asinkron operasi. GetObject

Impor

import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import java.nio.file.Paths; import java.util.concurrent.CompletableFuture;

Kode

/** * To run this AWS code example, ensure that you have setup your development environment, including your AWS credentials. * * For information, see this documentation topic: * * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html */ public class S3AsyncStreamOps { public static void main(String[] args) { final String USAGE = "\n" + "Usage:\n" + " S3AsyncStreamOps <bucketName> <objectKey> <path>\n\n" + "Where:\n" + " bucketName - the name of the Amazon S3 bucket (for example, bucket1). \n\n" + " objectKey - the name of the object (for example, book.pdf). \n" + " path - the local path to the file (for example, C:/AWS/book.pdf). \n" ; if (args.length != 3) { System.out.println(USAGE); System.exit(1); } String bucketName = args[0]; String objectKey = args[1]; String path = args[2]; Region region = Region.US_WEST_2; S3AsyncClient client = S3AsyncClient.builder() .region(region) .build(); GetObjectRequest objectRequest = GetObjectRequest.builder() .bucket(bucketName) .key(objectKey) .build(); CompletableFuture<GetObjectResponse> futureGet = client.getObject(objectRequest, AsyncResponseTransformer.toFile(Paths.get(path))); futureGet.whenComplete((resp, err) -> { try { if (resp != null) { System.out.println("Object downloaded. Details: "+resp); } else { err.printStackTrace(); } } finally { // Only close the client when you are completely done with it client.close(); } }); futureGet.join(); } }

Konfigurasikan opsi asinkron lanjutan

AWS SDK for Java 2.x menggunakan Netty, kerangka kerja aplikasi jaringan berbasis peristiwa asinkron, untuk menangani utas I/O. AWS SDK for Java 2.x membuat Netty ExecutorService di belakang, untuk menyelesaikan futures yang dikembalikan dari permintaan klien HTTP hingga ke klien Netty. Abstraksi ini mengurangi risiko aplikasi merusak proses asinkron jika pengembang memilih untuk menghentikan atau menidurkan utas. Secara default, setiap klien asinkron membuat threadpool berdasarkan jumlah prosesor dan mengelola tugas dalam antrian di dalam file. ExecutorService

Anda dapat menentukan implementasi JDK tertentu ExecutorService ketika Anda membangun klien asinkron Anda. Cuplikan berikut membuat ExecutorService dengan jumlah thread tetap.

Kode

S3AsyncClient clientThread = S3AsyncClient.builder() .asyncConfiguration( b -> b.advancedOption(SdkAdvancedAsyncClientOption .FUTURE_COMPLETION_EXECUTOR, Executors.newFixedThreadPool(10) ) ) .build();

Untuk mengoptimalkan kinerja, Anda dapat mengelola pelaksana kumpulan utas Anda sendiri, dan menyertakannya saat mengonfigurasi klien Anda.

ThreadPoolExecutor executor = new ThreadPoolExecutor(50, 50, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(<custom_value>), new ThreadFactoryBuilder() .threadNamePrefix("sdk-async-response").build()); // Allow idle core threads to time out executor.allowCoreThreadTimeOut(true); S3AsyncClient clientThread = S3AsyncClient.builder() .asyncConfiguration( b -> b.advancedOption(SdkAdvancedAsyncClientOption .FUTURE_COMPLETION_EXECUTOR, executor ) ) .build();