

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 适用于 Java 的 AWS SDK 1.x 和 2.x 有什么区别
<a name="migration-whats-different"></a>

本节介绍将应用程序从使用 1.x 版本转换为 2.x 适用于 Java 的 AWS SDK 版本时需要注意的主要更改。

## 软件包名称更改
<a name="mig-diff-package-name-change"></a>

从 SDK for Java 1.x 到 SDK for Java 2.x 的一个明显变化是软件包名称的更改。软件包名称在 SDK 2.x 中以 `software.amazon.awssdk` 开头，而 SDK 1.x 则使用 `com.amazonaws`。

这些名称区分了 SDK 1.x 与 SDK 2.x 的 Maven 构件。SDK 2.x 的 Maven 构件使用 `software.amazon.awssdk` groupId，而 SDK 1.x 使用 `com.amazonaws` groupId。

有些时候，您的代码会要求项目具有 `com.amazonaws` 依赖项，而该项目原本只使用 SDK 2.x 构件。这方面的一个例子是使用服务器端 AWS Lambda。本指南前面的[设置 Apache Maven 项目](setup-project-maven.md#modules-dependencies)部分对此进行了介绍。

**注意**  
SDK 1.x 中的几个软件包名称包含 `v2`。在这种情况下，使用 `v2` 通常表示软件包中的代码旨在与相关服务的版本 2 配合使用。  
由于软件包的完整名称以 `com.amazonaws` 开头，因此这些是 SDK 1.x 组件。SDK 1.x 中这些软件包名称的示例有：  
`com.amazonaws.services.dynamodbv2`
`com.amazonaws.retry.v2`
`com.amazonaws.services.apigatewayv2`
`com.amazonaws.services.simpleemailv2`

## 将版本 2.x 添加到您的项目
<a name="adding-v2"></a>

使用 适用于 Java 的 AWS SDK 2.x 时，推荐使用 Maven 来管理依赖关系。要将版本 2.x 组件添加到您的项目，只需使用 SDK 上的依赖项来更新 `pom.xml` 文件。

**Example**  

```
<dependencyManagement>
    <dependencies>
        <dependency>
          <groupId>software.amazon.awssdk</groupId>
          <artifactId>bom</artifactId>
          <version>2.27.21</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>dynamodb</artifactId>
    </dependency>
</dependencies>
```

在将项目迁移到 [2.x 版本时 side-by-side，也可以使用 1.x 和 2.x](migration-side-by-side.md) 版本。

## 不可变 POJOs
<a name="immutable-classes"></a>

客户端和操作的请求和响应对象现在不可变，并且在创建之后不能更改。要重复使用一个请求或响应变量，您必须生成一个要分配给该请求或响应变量的新对象。

**Example 在 1.x 中更新请求对象**  

```
DescribeAlarmsRequest request = new DescribeAlarmsRequest();
DescribeAlarmsResult response = cw.describeAlarms(request);

request.setNextToken(response.getNextToken());
```

**Example 在 2.x 中更新请求对象**  

```
DescribeAlarmsRequest request = DescribeAlarmsRequest.builder().build();
DescribeAlarmsResponse response = cw.describeAlarms(request);

request = DescribeAlarmsRequest.builder()
        .nextToken(response.nextToken())
        .build();
```

## Setter 和 getter 方法
<a name="setter-getter-methods"></a>

在 适用于 Java 的 AWS SDK 2.x 中，setter 方法名称不包含`set`或`with`前缀。例如，`*.withEndpoint()` 现为 `*.endpoint()`。

Getter 方法名称不使用 `get` 前缀。

**Example 在 1.x 中使用 setter 方法**  

```
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard()
        		.withRegion("us-east-1")
        		.build();
```

**Example 在 2.x 中使用 setter 方法**  

```
DynamoDbClient client = DynamoDbClient.builder()
        		.region(Region.US_EAST_1)
        		.build();
```

**Example 在 1.x 中使用 getter 方法**  

```
String token = request.getNextToken();
```

**Example 在 2.x 中使用 getter 方法**  

```
String token = request.nextToken();
```

## 模型类名
<a name="model-classname-changes"></a>

代表服务响应的模型类名在 v2 中以 `Response` 结尾，而不是以 v1 使用的 `Result` 结尾。

**Example 在 v1 中代表响应的类名**  

```
CreateApiKeyResult
AllocateAddressResult
```

**Example 在 v2 中代表响应的类名**  

```
CreateApiKeyResponse
AllocateAddressResponse
```

## 库和实用工具的迁移状态
<a name="migration-libraries-utilities"></a>

### 适用于 Java 的 SDK 库和实用工具
<a name="migration-java-sdk-libs-utils"></a>

下表列出了适用于 Java 的 SDK 库和实用工具的迁移状态。


| 版本 1.12.x 中的名称 | 版本 2.x 中的名称 | 自 2.x 的以下版本起 | 
| --- | --- | --- | 
| 迪纳摩 DBMapper | [DynamoDbEnhancedClient](dynamodb-enhanced-client.md) | 2.12.0 | 
| Waiter | [Waiter](waiters.md) | 2.15.0 | 
| CloudFrontUrlSigner, CloudFrontCookieSigner | [CloudFrontUtilities](https://aws.amazon.com/blogs/developer/amazon-cloudfront-signed-urls-and-cookies-are-now-supported-in-aws-sdk-for-java-2-x/) | 2.18.33 | 
| TransferManager | [S3TransferManager](transfer-manager.md) | 2.19.0 | 
| EC2 元数据客户端 |  [EC2 元数据客户端](examples-ec2-IMDS.md)  | 2.19.29 | 
| S3 URI 解析器 |  [S3 URI 解析器](https://aws.amazon.com/blogs/devops/s3-uri-parsing-is-now-available-in-aws-sdk-for-java-2-x/)  | 2.20.41 | 
| IAM policy 生成器 | [IAM policy 生成器](feature-iam-policy-builder.md) | 2.20.126 | 
| S3 事件通知 | [S3 事件通知](examples-s3-event-notifications.md#s3-event-notification-read) | 2.25.11  | 
| Amazon SQS 客户端缓存 | [适用于 Amazon SQS 的自动请求批处理 API](sqs-auto-batch.md) | 2.28.0 | 
| 进程侦听程序 | 进程侦听程序 | [尚未发布](https://github.com/aws/aws-sdk-java-v2/issues/25) | 

### 相关库
<a name="migration-other-sdks"></a>

下表列出了单独发布但可与适用于 Java 的 SDK 2.x 配合使用的库。


| 适用于 Java 的 SDK 2.x 中使用的名称 | 最低版本 | 
| --- | --- | 
|  [Amazon S3 加密客户端](https://docs.aws.amazon.com/amazon-s3-encryption-client/latest/developerguide/what-is-s3-encryption-client.html)  |  3.0.0 1  | 
| [AWS 适用于 DynamoDB 的数据库加密 SDK](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/ddb-java.html) | 3.0.0 2 | 

#### 1Amazon S3 加密客户端
<a name="migration-s3-encryption-sdk"></a>

适用于 Amazon S3 的加密客户端可通过使用以下 Maven 依赖项获得。

```
<dependency>
    <groupId>software.amazon.encryption.s3</groupId>
    <artifactId>amazon-s3-encryption-client-java</artifactId>
    <version>3.x</version>
</dependency>
```

#### 2 适用于 DynamoDB 的AWS 数据库加密 SDK
<a name="migration-ddb-encryption-sdk"></a>

通过使用以下 Maven 依赖项，适用于 DynamoDB 的 AWS 数据库加密 SDK 可用于 V2。

```
<dependency> 
    <groupId>software.amazon.cryptography</groupId>
    <artifactId>aws-database-encryption-sdk-dynamodb</artifactId>
    <version>3.x</version>
</dependency>
```

[数据库加密软件开发工具包开发人员指南（名为 Java 版 Amazon DynamoDB 加密客户端）和中AWS 提供了与 Java 软件开发工具包版本 1 配合使用的 D *ynamoDB* 加密](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/java.html)库的信息。[GitHub](https://github.com/aws/aws-dynamodb-encryption-java)

[有关与 Java SDK 版本 2 兼容的 DynamoDB 加密库的更多信息，请参阅[AWS 数据库加密 SDK 开发人员](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/ddb-java.html)指南和源代码。GitHub](https://github.com/aws/aws-database-encryption-sdk-dynamodb)

《[AWS 数据库加密 SDK 开发人员指南](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/ddb-java-migrate.html)》中提供了有关加密库的迁移信息。

### 库和实用工具的迁移详细信息
<a name="migrate-libs-utils-details"></a>
+ [Transfer Manager](migration-s3-transfer-manager.md)
+ [EC2 元数据实用程序](migration-imds.md)
+ [CloudFront预先签名](migration-cloudfront-presigning.md)
+ [S3 URI 解析](migration-s3-uri-parser.md)
+ [DynamoDB mapping/document APIs](migration-ddb-mapper.md) 
+ [IAM 策略生成器](migration-iam-policy-builder.md)
+ [S3 事件通知](migration-s3-event-notification.md)
+ SDK 指标发布（[1.x 文档](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/generating-sdk-metrics.html)、[2.x](metrics.md) 文档）

# 客户端更改
<a name="migration-clients"></a>

## 客户端生成器
<a name="client-builder"></a>

您必须使用客户端生成器方法来创建所有客户端。构造函数不再可用。

**Example 在版本 1.x 中创建客户端**  

```
AmazonDynamoDB ddbClient = AmazonDynamoDBClientBuilder.defaultClient();
AmazonDynamoDBClient ddbClient = new AmazonDynamoDBClient();
```

**Example 在版本 2.x 中创建客户端**  

```
DynamoDbClient ddbClient = DynamoDbClient.create();
DynamoDbClient ddbClient = DynamoDbClient.builder().build();
```

## 客户端类名
<a name="class-names"></a>

所有客户端类名现在完全采用驼峰大小写，且不再使用 `Amazon` 前缀。这些更改与 AWS CLI中使用的名称保持一致。

**Example 1.x 中的类名**  

```
AmazonDynamoDB
AWSACMPCAAsyncClient
```

**Example 2.x 中的类名**  

```
DynamoDbClient
AcmAsyncClient
```


**客户端类名更改**  

| 1.x 客户端 | 2.x 客户端 | 
| --- | --- | 
| com.amazonaws.services.acmpca.AWSACMPCAAsyncClient | software.amazon.awssdk.services.acm.AcmAsyncClient | 
| com.amazonaws.services.acmpca.AWSACMPCAClient | software.amazon.awssdk.services.acm.AcmClient | 
| com.amazonaws.services.alexaforbusiness.AmazonAlexaForBusinessAsyncClient | software.amazon.awssdk.services.alexaforbusiness.AlexaForBusinessAsyncClient | 
| com.amazonaws.services.alexaforbusiness.AmazonAlexaForBusinessClient | software.amazon.awssdk.services.alexaforbusiness.AlexaForBusinessClient | 
| com.amazonaws.services.apigateway.AmazonApiGatewayAsyncClient | software.amazon.awssdk.services.apigateway.ApiGatewayAsyncClient | 
| com.amazonaws.services.apigateway.AmazonApiGatewayClient | software.amazon.awssdk.services.apigateway.ApiGatewayClient | 
| com.amazonaws.services.applicationautoscaling.AWSApplicationAutoScalingAsyncClient | software.amazon.awssdk.services.applicationautoscaling.ApplicationAutoScalingAsyncClient | 
| com.amazonaws.services.applicationautoscaling.AWSApplicationAutoScalingClient | software.amazon.awssdk.services.applicationautoscaling.ApplicationAutoScalingClient | 
| com.amazonaws.services.applicationdiscovery.AWSApplicationDiscoveryAsyncClient | software.amazon.awssdk.services.applicationdiscovery.ApplicationDiscoveryAsyncClient | 
| com.amazonaws.services.applicationdiscovery.AWSApplicationDiscoveryClient | software.amazon.awssdk.services.applicationdiscovery.ApplicationDiscoveryClient | 
| com.amazonaws.services.appstream.AmazonAppStreamAsyncClient | software.amazon.awssdk.services.appstream.AppStreamAsyncClient | 
| com.amazonaws.services.appstream.AmazonAppStreamClient | software.amazon.awssdk.services.appstream.AppStreamClient | 
| com.amazonaws.services.appsync.AWSAppSyncAsyncClient | software.amazon.awssdk.services.appsync.AppSyncAsyncClient | 
| com.amazonaws.services.appsync.AWSAppSyncClient | software.amazon.awssdk.services.appsync.AppSyncClient | 
| com.amazonaws.services.athena.AmazonAthenaAsyncClient | software.amazon.awssdk.services.athena.AthenaAsyncClient | 
| com.amazonaws.services.athena.AmazonAthenaClient | software.amazon.awssdk.services.athena.AthenaClient | 
| com.amazonaws.services.autoscaling.AmazonAutoScalingAsyncClient | software.amazon.awssdk.services.autoscaling.AutoScalingAsyncClient | 
| com.amazonaws.services.autoscaling.AmazonAutoScalingClient | software.amazon.awssdk.services.autoscaling.AutoScalingClient | 
| com.amazonaws.services.autoscalingplans.AWSAutoScalingPlansAsyncClient | software.amazon.awssdk.services.autoscalingplans.AutoScalingPlansAsyncClient | 
| com.amazonaws.services.autoscalingplans.AWSAutoScalingPlansClient | software.amazon.awssdk.services.autoscalingplans.AutoScalingPlansClient | 
| com.amazonaws.services.batch.AWSBatchAsyncClient | software.amazon.awssdk.services.batch.BatchAsyncClient | 
| com.amazonaws.services.batch.AWSBatchClient | software.amazon.awssdk.services.batch.BatchClient | 
| com.amazonaws.services.budgets.AWSBudgetsAsyncClient | software.amazon.awssdk.services.budgets.BudgetsAsyncClient | 
| com.amazonaws.services.budgets.AWSBudgetsClient | software.amazon.awssdk.services.budgets.BudgetsClient | 
| com.amazonaws.services.certificatemanager.AWSCertificateManagerAsyncClient | software.amazon.awssdk.services.acm.AcmAsyncClient | 
| com.amazonaws.services.certificatemanager.AWSCertificateManagerClient | software.amazon.awssdk.services.acm.AcmClient | 
| com.amazonaws.services.cloud9.AWSCloud9AsyncClient | software.amazon.awssdk.services.cloud9.Cloud9AsyncClient | 
| com.amazonaws.services.cloud9.AWSCloud9Client | software.amazon.awssdk.services.cloud9.Cloud9Client | 
| com.amazonaws.services.clouddirectory.AmazonCloudDirectoryAsyncClient | software.amazon.awssdk.services.clouddirectory.CloudDirectoryAsyncClient | 
| com.amazonaws.services.clouddirectory.AmazonCloudDirectoryClient | software.amazon.awssdk.services.clouddirectory.CloudDirectoryClient | 
| com.amazonaws.services.cloudformation.AmazonCloudFormationAsyncClient | software.amazon.awssdk.services.cloudformation.CloudFormationAsyncClient | 
| com.amazonaws.services.cloudformation.AmazonCloudFormationClient | software.amazon.awssdk.services.cloudformation.CloudFormationClient | 
| com.amazonaws.services.cloudfront.AmazonCloudFrontAsyncClient | software.amazon.awssdk.services.cloudfront.CloudFrontAsyncClient | 
| com.amazonaws.services.cloudfront.AmazonCloudFrontClient | software.amazon.awssdk.services.cloudfront.CloudFrontClient | 
| com.amazonaws.services.cloudhsm.AWSCloudHSMAsyncClient | software.amazon.awssdk.services.cloudhsm.CloudHsmAsyncClient | 
| com.amazonaws.services.cloudhsm.AWSCloudHSMClient | software.amazon.awssdk.services.cloudhsm.CloudHsmClient | 
| com.amazonaws.services.cloudhsmv2.AWSCloudHSMV2AsyncClient | software.amazon.awssdk.services.cloudhsmv2.CloudHsmV2AsyncClient | 
| com.amazonaws.services.cloudhsmv2.AWSCloudHSMV2Client | software.amazon.awssdk.services.cloudhsmv2.CloudHsmV2Client | 
| com.amazonaws.services.cloudsearchdomain.AmazonCloudSearchDomainAsyncClient | software.amazon.awssdk.services.cloudsearchdomain.CloudSearchDomainAsyncClient | 
| com.amazonaws.services.cloudsearchdomain.AmazonCloudSearchDomainClient | software.amazon.awssdk.services.cloudsearchdomain.CloudSearchDomainClient | 
| com.amazonaws.services.cloudsearchv2.AmazonCloudSearchAsyncClient | software.amazon.awssdk.services.cloudsearch.CloudSearchAsyncClient | 
| com.amazonaws.services.cloudsearchv2.AmazonCloudSearchClient | software.amazon.awssdk.services.cloudsearch.CloudSearchClient | 
| com.amazonaws.services.cloudtrail.AWSCloudTrailAsyncClient | software.amazon.awssdk.services.cloudtrail.CloudTrailAsyncClient | 
| com.amazonaws.services.cloudtrail.AWSCloudTrailClient | software.amazon.awssdk.services.cloudtrail.CloudTrailClient | 
| com.amazonaws.services.cloudwatch.AmazonCloudWatchAsyncClient | software.amazon.awssdk.services.cloudwatch.CloudWatchAsyncClient | 
| com.amazonaws.services.cloudwatch.AmazonCloudWatchClient | software.amazon.awssdk.services.cloudwatch.CloudWatchClient | 
| com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEventsAsyncClient | software.amazon.awssdk.services.cloudwatchevents.CloudWatchEventsAsyncClient | 
| com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEventsClient | software.amazon.awssdk.services.cloudwatchevents.CloudWatchEventsClient | 
| com.amazonaws.services.codebuild.AWSCodeBuildAsyncClient | software.amazon.awssdk.services.codebuild.CodeBuildAsyncClient | 
| com.amazonaws.services.codebuild.AWSCodeBuildClient | software.amazon.awssdk.services.codebuild.CodeBuildClient | 
| com.amazonaws.services.codecommit.AWSCodeCommitAsyncClient | software.amazon.awssdk.services.codecommit.CodeCommitAsyncClient | 
| com.amazonaws.services.codecommit.AWSCodeCommitClient | software.amazon.awssdk.services.codecommit.CodeCommitClient | 
| com.amazonaws.services.codedeploy.AmazonCodeDeployAsyncClient | software.amazon.awssdk.services.codedeploy.CodeDeployAsyncClient | 
| com.amazonaws.services.codedeploy.AmazonCodeDeployClient | software.amazon.awssdk.services.codedeploy.CodeDeployClient | 
| com.amazonaws.services.codepipeline.AWSCodePipelineAsyncClient | software.amazon.awssdk.services.codepipeline.CodePipelineAsyncClient | 
| com.amazonaws.services.codepipeline.AWSCodePipelineClient | software.amazon.awssdk.services.codepipeline.CodePipelineClient | 
| com.amazonaws.services.codestar.AWSCodeStarAsyncClient | software.amazon.awssdk.services.codestar.CodeStarAsyncClient | 
| com.amazonaws.services.codestar.AWSCodeStarClient | software.amazon.awssdk.services.codestar.CodeStarClient | 
| com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityAsyncClient | software.amazon.awssdk.services.cognitoidentity.CognitoIdentityAsyncClient | 
| com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityClient | software.amazon.awssdk.services.cognitoidentity.CognitoIdentityClient | 
| com.amazonaws.services.cognitoidp.AWSCognitoIdentityProviderAsyncClient | software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderAsyncClient | 
| com.amazonaws.services.cognitoidp.AWSCognitoIdentityProviderClient | software.amazon.awssdk.services.cognitoidentityprovider.CognitoIdentityProviderClient | 
| com.amazonaws.services.cognitosync.AmazonCognitoSyncAsyncClient | software.amazon.awssdk.services.cognitosync.CognitoSyncAsyncClient | 
| com.amazonaws.services.cognitosync.AmazonCognitoSyncClient | software.amazon.awssdk.services.cognitosync.CognitoSyncClient | 
| com.amazonaws.services.comprehend.AmazonComprehendAsyncClient | software.amazon.awssdk.services.comprehend.ComprehendAsyncClient | 
| com.amazonaws.services.comprehend.AmazonComprehendClient | software.amazon.awssdk.services.comprehend.ComprehendClient | 
| com.amazonaws.services.config.AmazonConfigAsyncClient | software.amazon.awssdk.services.config.ConfigAsyncClient | 
| com.amazonaws.services.config.AmazonConfigClient | software.amazon.awssdk.services.config.ConfigClient | 
| com.amazonaws.services.connect.AmazonConnectAsyncClient | software.amazon.awssdk.services.connect.ConnectAsyncClient | 
| com.amazonaws.services.connect.AmazonConnectClient | software.amazon.awssdk.services.connect.ConnectClient | 
| com.amazonaws.services.costandusagereport.AWSCostAndUsageReportAsyncClient | software.amazon.awssdk.services.costandusagereport.CostAndUsageReportAsyncClient | 
| com.amazonaws.services.costandusagereport.AWSCostAndUsageReportClient | software.amazon.awssdk.services.costandusagereport.CostAndUsageReportClient | 
| com.amazonaws.services.costexplorer.AWSCostExplorerAsyncClient | software.amazon.awssdk.services.costexplorer.CostExplorerAsyncClient | 
| com.amazonaws.services.costexplorer.AWSCostExplorerClient | software.amazon.awssdk.services.costexplorer.CostExplorerClient | 
| com.amazonaws.services.databasemigrationservice.AWSDatabaseMigrationServiceAsyncClient | software.amazon.awssdk.services.databasemigration.DatabaseMigrationAsyncClient | 
| com.amazonaws.services.databasemigrationservice.AWSDatabaseMigrationServiceClient | software.amazon.awssdk.services.databasemigration.DatabaseMigrationClient | 
| com.amazonaws.services.datapipeline.DataPipelineAsyncClient | software.amazon.awssdk.services.datapipeline.DataPipelineAsyncClient | 
| com.amazonaws.services.datapipeline.DataPipelineClient | software.amazon.awssdk.services.datapipeline.DataPipelineAsyncClient | 
| com.amazonaws.services.dax.AmazonDaxAsyncClient | software.amazon.awssdk.services.dax.DaxAsyncClient | 
| com.amazonaws.services.dax.AmazonDaxClient | software.amazon.awssdk.services.dax.DaxClient | 
| com.amazonaws.services.devicefarm.AWSDeviceFarmAsyncClient | software.amazon.awssdk.services.devicefarm.DeviceFarmAsyncClient | 
| com.amazonaws.services.devicefarm.AWSDeviceFarmClient | software.amazon.awssdk.services.devicefarm.DeviceFarmClient | 
| com.amazonaws.services.directconnect.AmazonDirectConnectAsyncClient | software.amazon.awssdk.services.directconnect.DirectConnectAsyncClient | 
| com.amazonaws.services.directconnect.AmazonDirectConnectClient | software.amazon.awssdk.services.directconnect.DirectConnectClient | 
| com.amazonaws.services.directory.AWSDirectoryServiceAsyncClient | software.amazon.awssdk.services.directory.DirectoryAsyncClient | 
| com.amazonaws.services.directory.AWSDirectoryServiceClient | software.amazon.awssdk.services.directory.DirectoryClient | 
| com.amazonaws.services.dlm.AmazonDLMAsyncClient | software.amazon.awssdk.services.dlm.DlmAsyncClient | 
| com.amazonaws.services.dlm.AmazonDLMClient | software.amazon.awssdk.services.dlm.DlmClient | 
| com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsyncClient | software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient | 
| com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient | software.amazon.awssdk.services.dynamodb.DynamoDbClient | 
| com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsAsyncClient | software.amazon.awssdk.services.dynamodb.streams.DynamoDbStreamsAsyncClient | 
| com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsClient | software.amazon.awssdk.services.dynamodb.streams.DynamoDbStreamsClient | 
| com.amazonaws.services.ec2.AmazonEC2AsyncClient | software.amazon.awssdk.services.ec2.Ec2AsyncClient | 
| com.amazonaws.services.ec2.AmazonEC2Client | software.amazon.awssdk.services.ec2.Ec2Client | 
| com.amazonaws.services.ecr.AmazonECRAsyncClient | software.amazon.awssdk.services.ecr.EcrAsyncClient | 
| com.amazonaws.services.ecr.AmazonECRClient | software.amazon.awssdk.services.ecr.EcrClient | 
| com.amazonaws.services.ecs.AmazonECSAsyncClient | software.amazon.awssdk.services.ecs.EcsAsyncClient | 
| com.amazonaws.services.ecs.AmazonECSClient | software.amazon.awssdk.services.ecs.EcsClient | 
| com.amazonaws.services.eks.AmazonEKSAsyncClient | software.amazon.awssdk.services.eks.EksAsyncClient | 
| com.amazonaws.services.eks.AmazonEKSClient | software.amazon.awssdk.services.eks.EksClient | 
| com.amazonaws.services.elasticache.AmazonElastiCacheAsyncClient | software.amazon.awssdk.services.elasticache.ElastiCacheAsyncClient | 
| com.amazonaws.services.elasticache.AmazonElastiCacheClient | software.amazon.awssdk.services.elasticache.ElastiCacheClient | 
| com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalkAsyncClient | software.amazon.awssdk.services.elasticbeanstalk.ElasticBeanstalkAsyncClient | 
| com.amazonaws.services.elasticbeanstalk.AWSElasticBeanstalkClient | software.amazon.awssdk.services.elasticbeanstalk.ElasticBeanstalkClient | 
| com.amazonaws.services.elasticfilesystem.AmazonElasticFileSystemAsyncClient | software.amazon.awssdk.services.efs.EfsAsyncClient | 
| com.amazonaws.services.elasticfilesystem.AmazonElasticFileSystemClient | software.amazon.awssdk.services.efs.EfsClient | 
| com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingAsyncClient | software.amazon.awssdk.services.elasticloadbalancing.ElasticLoadBalancingAsyncClient | 
| com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingClient | software.amazon.awssdk.services.elasticloadbalancing.ElasticLoadBalancingClient | 
| com.amazonaws.services.elasticloadbalancingv2.AmazonElasticLoadBalancingAsyncClient | software.amazon.awssdk.services.elasticloadbalancingv2.ElasticLoadBalancingV2AsyncClient | 
| com.amazonaws.services.elasticloadbalancingv2.AmazonElasticLoadBalancingClient | software.amazon.awssdk.services.elasticloadbalancingv2.ElasticLoadBalancingV2Client | 
| com.amazonaws.services.elasticmapreduce.AmazonElasticMapReduceAsyncClient | software.amazon.awssdk.services.emr.EmrAsyncClient | 
| com.amazonaws.services.elasticmapreduce.AmazonElasticMapReduceClient | software.amazon.awssdk.services.emr.EmrClient | 
| com.amazonaws.services.elasticsearch.AWSElasticsearchAsyncClient | software.amazon.awssdk.services.elasticsearch.ElasticsearchAsyncClient | 
| com.amazonaws.services.elasticsearch.AWSElasticsearchClient | software.amazon.awssdk.services.elasticsearch.ElasticsearchClient | 
| com.amazonaws.services.elastictranscoder.AmazonElasticTranscoderAsyncClient | software.amazon.awssdk.services.elastictranscoder.ElasticTranscoderAsyncClient | 
| com.amazonaws.services.elastictranscoder.AmazonElasticTranscoderClient | software.amazon.awssdk.services.elastictranscoder.ElasticTranscoderClient | 
| com.amazonaws.services.fms.AWSFMSAsyncClient | software.amazon.awssdk.services.fms.FmsAsyncClient | 
| com.amazonaws.services.fms.AWSFMSClient | software.amazon.awssdk.services.fms.FmsClient | 
| com.amazonaws.services.gamelift.AmazonGameLiftAsyncClient | software.amazon.awssdk.services.gamelift.GameLiftAsyncClient | 
| com.amazonaws.services.gamelift.AmazonGameLiftClient | software.amazon.awssdk.services.gamelift.GameLiftClient | 
| com.amazonaws.services.glacier.AmazonGlacierAsyncClient | software.amazon.awssdk.services.glacier.GlacierAsyncClient | 
| com.amazonaws.services.glacier.AmazonGlacierClient | software.amazon.awssdk.services.glacier.GlacierClient | 
| com.amazonaws.services.glue.AWSGlueAsyncClient | software.amazon.awssdk.services.glue.GlueAsyncClient | 
| com.amazonaws.services.glue.AWSGlueClient | software.amazon.awssdk.services.glue.GlueClient | 
| com.amazonaws.services.greengrass.AWSGreengrassAsyncClient | software.amazon.awssdk.services.greengrass.GreengrassAsyncClient | 
| com.amazonaws.services.greengrass.AWSGreengrassClient | software.amazon.awssdk.services.greengrass.GreengrassClient | 
| com.amazonaws.services.guardduty.AmazonGuardDutyAsyncClient | software.amazon.awssdk.services.guardduty.GuardDutyAsyncClient | 
| com.amazonaws.services.guardduty.AmazonGuardDutyClient | software.amazon.awssdk.services.guardduty.GuardDutyClient | 
| com.amazonaws.services.health.AWSHealthAsyncClient | software.amazon.awssdk.services.health.HealthAsyncClient | 
| com.amazonaws.services.health.AWSHealthClient | software.amazon.awssdk.services.health.HealthClient | 
| com.amazonaws.services.identitymanagement.AmazonIdentityManagementAsyncClient | software.amazon.awssdk.services.iam.IamAsyncClient | 
| com.amazonaws.services.identitymanagement.AmazonIdentityManagementClient | software.amazon.awssdk.services.iam.IamClient | 
| com.amazonaws.services.importexport.AmazonImportExportAsyncClient | Deprecated | 
| com.amazonaws.services.importexport.AmazonImportExportClient | Deprecated | 
| com.amazonaws.services.inspector.AmazonInspectorAsyncClient | software.amazon.awssdk.services.inspector.InspectorAsyncClient | 
| com.amazonaws.services.inspector.AmazonInspectorClient | software.amazon.awssdk.services.inspector.InspectorClient | 
| com.amazonaws.services.iot.AWSIotAsyncClient | software.amazon.awssdk.services.iot.IotAsyncClient | 
| com.amazonaws.services.iot.AWSIotClient | software.amazon.awssdk.services.iot.IotClient | 
| com.amazonaws.services.iot1clickdevices.AWSIoT1ClickDevicesAsyncClient | software.amazon.awssdk.services.iot1clickdevices.Iot1ClickDevicesAsyncClient | 
| com.amazonaws.services.iot1clickdevices.AWSIoT1ClickDevicesClient | software.amazon.awssdk.services.iot1clickdevices.Iot1ClickDevicesClient | 
| com.amazonaws.services.iot1clickprojects.AWSIoT1ClickProjectsAsyncClient | software.amazon.awssdk.services.iot1clickprojects.Iot1ClickProjectsAsyncClient | 
| com.amazonaws.services.iot1clickprojects.AWSIoT1ClickProjectsClient | software.amazon.awssdk.services.iot1clickprojects.Iot1ClickProjectsClient | 
| com.amazonaws.services.iotanalytics.AWSIoTAnalyticsAsyncClient | software.amazon.awssdk.services.iotanalytics.IotAnalyticsAsyncClient | 
| com.amazonaws.services.iotanalytics.AWSIoTAnalyticsClient | software.amazon.awssdk.services.iotanalytics.IotAnalyticsClient | 
| com.amazonaws.services.iotdata.AWSIotDataAsyncClient | software.amazon.awssdk.services.iotdata.IotDataAsyncClient | 
| com.amazonaws.services.iotdata.AWSIotDataClient | software.amazon.awssdk.services.iotdata.IotDataClient | 
| com.amazonaws.services.iotjobsdataplane.AWSIoTJobsDataPlaneAsyncClient | software.amazon.awssdk.services.iotdataplane.IotDataPlaneAsyncClient | 
| com.amazonaws.services.iotjobsdataplane.AWSIoTJobsDataPlaneClient | software.amazon.awssdk.services.iotdataplane.IotDataPlaneClient | 
| com.amazonaws.services.kinesis.AmazonKinesisAsyncClient | software.amazon.awssdk.services.kinesis.KinesisAsyncClient | 
| com.amazonaws.services.kinesis.AmazonKinesisClient | software.amazon.awssdk.services.kinesis.KinesisClient | 
| com.amazonaws.services.kinesisanalytics.AmazonKinesisAnalyticsAsyncClient | software.amazon.awssdk.services.kinesisanalytics.KinesisAnalyticsAsyncClient | 
| com.amazonaws.services.kinesisanalytics.AmazonKinesisAnalyticsClient | software.amazon.awssdk.services.kinesisanalytics.KinesisAnalyticsClient | 
| com.amazonaws.services.kinesisfirehose.AmazonKinesisFirehoseAsyncClient | software.amazon.awssdk.services.firehose.FirehoseAsyncClient | 
| com.amazonaws.services.kinesisfirehose.AmazonKinesisFirehoseClient | software.amazon.awssdk.services.firehose.FirehoseClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoArchivedMediaAsyncClient | software.amazon.awssdk.services.kinesisvideoarchivedmedia.KinesisVideoArchivedMediaAsyncClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoArchivedMediaClient | software.amazon.awssdk.services.kinesisvideoarchivedmedia.KinesisVideoArchivedMediaClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoAsyncClient | software.amazon.awssdk.services.kinesisvideo.KinesisVideoAsyncClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoClient | software.amazon.awssdk.services.kinesisvideo.KinesisVideoClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoMediaAsyncClient | software.amazon.awssdk.services.kinesisvideomedia.KinesisVideoMediaAsyncClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoMediaClient | software.amazon.awssdk.services.kinesisvideomedia.KinesisVideoMediaClient | 
| com.amazonaws.services.kinesisvideo.AmazonKinesisVideoPutMediaClient | 不支持  | 
| com.amazonaws.services.kms.AWSKMSAsyncClient | software.amazon.awssdk.services.kms.KmsAsyncClient | 
| com.amazonaws.services.kms.AWSKMSClient | software.amazon.awssdk.services.kms.KmsClient | 
| com.amazonaws.services.lambda.AWSLambdaAsyncClient | software.amazon.awssdk.services.lambda.LambdaAsyncClient | 
| com.amazonaws.services.lambda.AWSLambdaClient | software.amazon.awssdk.services.lambda.LambdaClient | 
| com.amazonaws.services.lexmodelbuilding.AmazonLexModelBuildingAsyncClient | software.amazon.awssdk.services.lexmodelbuilding.LexModelBuildingAsyncClient | 
| com.amazonaws.services.lexmodelbuilding.AmazonLexModelBuildingClient | software.amazon.awssdk.services.lexmodelbuilding.LexModelBuildingClient | 
| com.amazonaws.services.lexruntime.AmazonLexRuntimeAsyncClient | software.amazon.awssdk.services.lexruntime.LexRuntimeAsyncClient | 
| com.amazonaws.services.lexruntime.AmazonLexRuntimeClient | software.amazon.awssdk.services.lexruntime.LexRuntimeClient | 
| com.amazonaws.services.lightsail.AmazonLightsailAsyncClient | software.amazon.awssdk.services.lightsail.LightsailAsyncClient | 
| com.amazonaws.services.lightsail.AmazonLightsailClient | software.amazon.awssdk.services.lightsail.LightsailClient | 
| com.amazonaws.services.logs.AWSLogsAsyncClient | software.amazon.awssdk.services.logs.LogsAsyncClient | 
| com.amazonaws.services.logs.AWSLogsClient | software.amazon.awssdk.services.logs.LogsClient | 
| com.amazonaws.services.machinelearning.AmazonMachineLearningAsyncClient | software.amazon.awssdk.services.machinelearning.MachineLearningAsyncClient | 
| com.amazonaws.services.machinelearning.AmazonMachineLearningClient | software.amazon.awssdk.services.machinelearning.MachineLearningClient | 
| com.amazonaws.services.macie.AmazonMacieAsyncClient | software.amazon.awssdk.services.macie.MacieAsyncClient | 
| com.amazonaws.services.macie.AmazonMacieClient | software.amazon.awssdk.services.macie.MacieClient | 
| com.amazonaws.services.marketplacecommerceanalytics.AWSMarketplaceCommerceAnalyticsAsyncClient | software.amazon.awssdk.services.marketplacecommerceanalytics.MarketplaceCommerceAnalyticsAsyncClient | 
| com.amazonaws.services.marketplacecommerceanalytics.AWSMarketplaceCommerceAnalyticsClient | software.amazon.awssdk.services.marketplacecommerceanalytics.MarketplaceCommerceAnalyticsClient | 
| com.amazonaws.services.marketplaceentitlement.AWSMarketplaceEntitlementAsyncClient | software.amazon.awssdk.services.marketplaceentitlement.MarketplaceEntitlementAsyncClient | 
| com.amazonaws.services.marketplaceentitlement.AWSMarketplaceEntitlementClient | software.amazon.awssdk.services.marketplaceentitlement.MarketplaceEntitlementClient | 
| com.amazonaws.services.marketplacemetering.AWSMarketplaceMeteringAsyncClient | software.amazon.awssdk.services.marketplacemetering.MarketplaceMeteringAsyncClient | 
| com.amazonaws.services.marketplacemetering.AWSMarketplaceMeteringClient | software.amazon.awssdk.services.marketplacemetering.MarketplaceMeteringClient | 
| com.amazonaws.services.mediaconvert.AWSMediaConvertAsyncClient | software.amazon.awssdk.services.mediaconvert.MediaConvertAsyncClient | 
| com.amazonaws.services.mediaconvert.AWSMediaConvertClient | software.amazon.awssdk.services.mediaconvert.MediaConvertClient | 
| com.amazonaws.services.medialive.AWSMediaLiveAsyncClient | software.amazon.awssdk.services.medialive.MediaLiveAsyncClient | 
| com.amazonaws.services.medialive.AWSMediaLiveClient | software.amazon.awssdk.services.medialive.MediaLiveClient | 
| com.amazonaws.services.mediapackage.AWSMediaPackageAsyncClient | software.amazon.awssdk.services.mediapackage.MediaPackageAsyncClient | 
| com.amazonaws.services.mediapackage.AWSMediaPackageClient | software.amazon.awssdk.services.mediapackage.MediaPackageClient | 
| com.amazonaws.services.mediastore.AWSMediaStoreAsyncClient | software.amazon.awssdk.services.mediastore.MediaStoreAsyncClient | 
| com.amazonaws.services.mediastore.AWSMediaStoreClient | software.amazon.awssdk.services.mediastore.MediaStoreClient | 
| com.amazonaws.services.mediastoredata.AWSMediaStoreDataAsyncClient | software.amazon.awssdk.services.mediastoredata.MediaStoreDataAsyncClient | 
| com.amazonaws.services.mediastoredata.AWSMediaStoreDataClient | software.amazon.awssdk.services.mediastoredata.MediaStoreDataClient | 
| com.amazonaws.services.mediatailor.AWSMediaTailorAsyncClient | software.amazon.awssdk.services.mediatailor.MediaTailorAsyncClient | 
| com.amazonaws.services.mediatailor.AWSMediaTailorClient | software.amazon.awssdk.services.mediatailor.MediaTailorClient | 
| com.amazonaws.services.migrationhub.AWSMigrationHubAsyncClient | software.amazon.awssdk.services.migrationhub.MigrationHubAsyncClient | 
| com.amazonaws.services.migrationhub.AWSMigrationHubClient | software.amazon.awssdk.services.migrationhub.MigrationHubClient | 
| com.amazonaws.services.mobile.AWSMobileAsyncClient | software.amazon.awssdk.services.mobile.MobileAsyncClient | 
| com.amazonaws.services.mobile.AWSMobileClient | software.amazon.awssdk.services.mobile.MobileClient | 
| com.amazonaws.services.mq.AmazonMQAsyncClient | software.amazon.awssdk.services.mq.MqAsyncClient | 
| com.amazonaws.services.mq.AmazonMQClient | software.amazon.awssdk.services.mq.MqClient | 
| com.amazonaws.services.mturk.AmazonMTurkAsyncClient | software.amazon.awssdk.services.mturk.MTurkAsyncClient | 
| com.amazonaws.services.mturk.AmazonMTurkClient | software.amazon.awssdk.services.mturk.MTurkClient | 
| com.amazonaws.services.neptune.AmazonNeptuneAsyncClient | software.amazon.awssdk.services.neptune.NeptuneAsyncClient | 
| com.amazonaws.services.neptune.AmazonNeptuneClient | software.amazon.awssdk.services.neptune.NeptuneClient | 
| com.amazonaws.services.opsworks.AWSOpsWorksAsyncClient | software.amazon.awssdk.services.opsworks.OpsWorksAsyncClient | 
| com.amazonaws.services.opsworks.AWSOpsWorksClient | software.amazon.awssdk.services.opsworks.OpsWorksClient | 
| com.amazonaws.services.opsworkscm.AWSOpsWorksCMAsyncClient | software.amazon.awssdk.services.opsworkscm.OpsWorksCmAsyncClient | 
| com.amazonaws.services.opsworkscm.AWSOpsWorksCMClient | software.amazon.awssdk.services.opsworkscm.OpsWorksCmClient | 
| com.amazonaws.services.organizations.AWSOrganizationsAsyncClient | software.amazon.awssdk.services.organizations.OrganizationsAsyncClient | 
| com.amazonaws.services.organizations.AWSOrganizationsClient | software.amazon.awssdk.services.organizations.OrganizationsClient | 
| com.amazonaws.services.pi.AWSPIAsyncClient | software.amazon.awssdk.services.pi.PiAsyncClient | 
| com.amazonaws.services.pi.AWSPIClient | software.amazon.awssdk.services.pi.PiClient | 
| com.amazonaws.services.pinpoint.AmazonPinpointAsyncClient | software.amazon.awssdk.services.pinpoint.PinpointAsyncClient | 
| com.amazonaws.services.pinpoint.AmazonPinpointClient | software.amazon.awssdk.services.pinpoint.PinpointClient | 
| com.amazonaws.services.polly.AmazonPollyAsyncClient | software.amazon.awssdk.services.polly.PollyAsyncClient | 
| com.amazonaws.services.polly.AmazonPollyClient | software.amazon.awssdk.services.polly.PollyClient | 
| com.amazonaws.services.pricing.AWSPricingAsyncClient | software.amazon.awssdk.services.pricing.PricingAsyncClient | 
| com.amazonaws.services.pricing.AWSPricingClient | software.amazon.awssdk.services.pricing.PricingClient | 
| com.amazonaws.services.rds.AmazonRDSAsyncClient | software.amazon.awssdk.services.rds.RdsAsyncClient | 
| com.amazonaws.services.rds.AmazonRDSClient | software.amazon.awssdk.services.rds.RdsClient | 
| com.amazonaws.services.redshift.AmazonRedshiftAsyncClient | software.amazon.awssdk.services.redshift.RedshiftAsyncClient | 
| com.amazonaws.services.redshift.AmazonRedshiftClient | software.amazon.awssdk.services.redshift.RedshiftClient | 
| com.amazonaws.services.rekognition.AmazonRekognitionAsyncClient | software.amazon.awssdk.services.rekognition.RekognitionAsyncClient | 
| com.amazonaws.services.rekognition.AmazonRekognitionClient | software.amazon.awssdk.services.rekognition.RekognitionClient | 
| com.amazonaws.services.resourcegroups.AWSResourceGroupsAsyncClient | software.amazon.awssdk.services.resourcegroups.ResourceGroupsAsyncClient | 
| com.amazonaws.services.resourcegroups.AWSResourceGroupsClient | software.amazon.awssdk.services.resourcegroups.ResourceGroupsClient | 
| com.amazonaws.services.resourcegroupstaggingapi.AWSResourceGroupsTaggingAPIAsyncClient | software.amazon.awssdk.services.resourcegroupstaggingapi.ResourceGroupsTaggingApiAsyncClient | 
| com.amazonaws.services.resourcegroupstaggingapi.AWSResourceGroupsTaggingAPIClient | software.amazon.awssdk.services.resourcegroupstaggingapi.ResourceGroupsTaggingApiClient | 
| com.amazonaws.services.route53.AmazonRoute53AsyncClient | software.amazon.awssdk.services.route53.Route53AsyncClient | 
| com.amazonaws.services.route53.AmazonRoute53Client | software.amazon.awssdk.services.route53.Route53Client | 
| com.amazonaws.services.route53domains.AmazonRoute53DomainsAsyncClient | software.amazon.awssdk.services.route53domains.Route53DomainsAsyncClient | 
| com.amazonaws.services.route53domains.AmazonRoute53DomainsClient | software.amazon.awssdk.services.route53domains.Route53DomainsClient | 
| com.amazonaws.services.s3.AmazonS3Client | software.amazon.awssdk.services.s3.S3Client | 
| com.amazonaws.services.sagemaker.AmazonSageMakerAsyncClient | software.amazon.awssdk.services.sagemaker.SageMakerAsyncClient | 
| com.amazonaws.services.sagemaker.AmazonSageMakerClient | software.amazon.awssdk.services.sagemaker.SageMakerClient | 
| com.amazonaws.services.sagemakerruntime.AmazonSageMakerRuntimeAsyncClient | software.amazon.awssdk.services.sagemakerruntime.SageMakerRuntimeAsyncClient | 
| com.amazonaws.services.sagemakerruntime.AmazonSageMakerRuntimeClient | software.amazon.awssdk.services.sagemakerruntime.SageMakerRuntimeClient | 
| com.amazonaws.services.secretsmanager.AWSSecretsManagerAsyncClient | software.amazon.awssdk.services.secretsmanager.SecretsManagerAsyncClient | 
| com.amazonaws.services.secretsmanager.AWSSecretsManagerClient | software.amazon.awssdk.services.secretsmanager.SecretsManagerClient | 
| com.amazonaws.services.securitytoken.AWSSecurityTokenServiceAsyncClient | software.amazon.awssdk.services.sts.StsAsyncClient | 
| com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient | software.amazon.awssdk.services.sts.StsClient | 
| com.amazonaws.services.serverlessapplicationrepository.AWSServerlessApplicationRepositoryAsyncClient | software.amazon.awssdk.services.serverlessapplicationrepository.ServerlessApplicationRepositoryAsyncClient | 
| com.amazonaws.services.serverlessapplicationrepository.AWSServerlessApplicationRepositoryClient | software.amazon.awssdk.services.serverlessapplicationrepository.ServerlessApplicationRepositoryClient | 
| com.amazonaws.services.servermigration.AWSServerMigrationAsyncClient | software.amazon.awssdk.services.sms.SmsAsyncClient | 
| com.amazonaws.services.servermigration.AWSServerMigrationClient | software.amazon.awssdk.services.sms.SmsClient | 
| com.amazonaws.services.servicecatalog.AWSServiceCatalogAsyncClient | software.amazon.awssdk.services.servicecatalog.ServiceCatalogAsyncClient | 
| com.amazonaws.services.servicecatalog.AWSServiceCatalogClient | software.amazon.awssdk.services.servicecatalog.ServiceCatalogClient | 
| com.amazonaws.services.servicediscovery.AWSServiceDiscoveryAsyncClient | software.amazon.awssdk.services.servicediscovery.ServiceDiscoveryAsyncClient | 
| com.amazonaws.services.servicediscovery.AWSServiceDiscoveryClient | software.amazon.awssdk.services.servicediscovery.ServiceDiscoveryClient | 
| com.amazonaws.services.shield.AWSShieldAsyncClient | software.amazon.awssdk.services.shield.ShieldAsyncClient | 
| com.amazonaws.services.shield.AWSShieldClient | software.amazon.awssdk.services.shield.ShieldClient | 
| com.amazonaws.services.simpledb.AmazonSimpleDBAsyncClient | software.amazon.awssdk.services.simpledb.SimpleDbAsyncClient | 
| com.amazonaws.services.simpledb.AmazonSimpleDBClient | software.amazon.awssdk.services.simpledb.SimpleDbClient | 
| com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceAsyncClient | software.amazon.awssdk.services.ses.SesAsyncClient | 
| com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClient | software.amazon.awssdk.services.ses.SesClient | 
| com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementAsyncClient | software.amazon.awssdk.services.ssm.SsmAsyncClient | 
| com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementClient | software.amazon.awssdk.services.ssm.SsmClient | 
| com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowAsyncClient | software.amazon.awssdk.services.swf.SwfAsyncClient | 
| com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient | software.amazon.awssdk.services.swf.SwfClient | 
| com.amazonaws.services.snowball.AmazonSnowballAsyncClient | software.amazon.awssdk.services.snowball.SnowballAsyncClient | 
| com.amazonaws.services.snowball.AmazonSnowballClient | software.amazon.awssdk.services.snowball.SnowballClient | 
| com.amazonaws.services.sns.AmazonSNSAsyncClient | software.amazon.awssdk.services.sns.SnsAsyncClient | 
| com.amazonaws.services.sns.AmazonSNSClient | software.amazon.awssdk.services.sns.SnsClient | 
| com.amazonaws.services.sqs.AmazonSQSAsyncClient | software.amazon.awssdk.services.sqs.SqsAsyncClient | 
| com.amazonaws.services.sqs.AmazonSQSClient | software.amazon.awssdk.services.sqs.SqsClient | 
| com.amazonaws.services.stepfunctions.AWSStepFunctionsAsyncClient | software.amazon.awssdk.services.sfn.SfnAsyncClient | 
| com.amazonaws.services.stepfunctions.AWSStepFunctionsClient | software.amazon.awssdk.services.sfn.SfnClient | 
| com.amazonaws.services.storagegateway.AWSStorageGatewayAsyncClient | software.amazon.awssdk.services.storagegateway.StorageGatewayAsyncClient | 
| com.amazonaws.services.storagegateway.AWSStorageGatewayClient | software.amazon.awssdk.services.storagegateway.StorageGatewayClient | 
| com.amazonaws.services.support.AWSSupportAsyncClient | software.amazon.awssdk.services.support.SupportAsyncClient | 
| com.amazonaws.services.support.AWSSupportClient | software.amazon.awssdk.services.support.SupportClient | 
| com.amazonaws.services.transcribe.AmazonTranscribeAsyncClient | software.amazon.awssdk.services.transcribe.TranscribeAsyncClient | 
| com.amazonaws.services.transcribe.AmazonTranscribeClient | software.amazon.awssdk.services.transcribe.TranscribeClient | 
| com.amazonaws.services.translate.AmazonTranslateAsyncClient | software.amazon.awssdk.services.translate.TranslateAsyncClient | 
| com.amazonaws.services.translate.AmazonTranslateClient | software.amazon.awssdk.services.translate.TranslateClient | 
| com.amazonaws.services.waf.AWSWAFAsyncClient | software.amazon.awssdk.services.waf.WafAsyncClient | 
| com.amazonaws.services.waf.AWSWAFClient | software.amazon.awssdk.services.waf.WafClient | 
| com.amazonaws.services.waf.AWSWAFRegionalAsyncClient | software.amazon.awssdk.services.waf.regional.WafRegionalAsyncClient | 
| com.amazonaws.services.waf.AWSWAFRegionalClient | software.amazon.awssdk.services.waf.regional.WafRegionalClient | 
| com.amazonaws.services.workdocs.AmazonWorkDocsAsyncClient | software.amazon.awssdk.services.workdocs.WorkDocsAsyncClient | 
| com.amazonaws.services.workdocs.AmazonWorkDocsClient | software.amazon.awssdk.services.workdocs.WorkDocsClient | 
| com.amazonaws.services.workmail.AmazonWorkMailAsyncClient | software.amazon.awssdk.services.workmail.WorkMailAsyncClient | 
| com.amazonaws.services.workmail.AmazonWorkMailClient | software.amazon.awssdk.services.workmail.WorkMailClient | 
| com.amazonaws.services.workspaces.AmazonWorkspacesAsyncClient | software.amazon.awssdk.services.workspaces.WorkSpacesAsyncClient | 
| com.amazonaws.services.workspaces.AmazonWorkspacesClient | software.amazon.awssdk.services.workspaces.WorkSpacesClient | 
| com.amazonaws.services.xray.AWSXRayAsyncClient | software.amazon.awssdk.services.xray.XRayAsyncClient | 
| com.amazonaws.services.xray.AWSXRayClient | software.amazon.awssdk.services.xray.XRayClient | 

# 客户端创建默认设置
<a name="client-creation-defaults"></a>

在版本 2.x 中，对默认客户端创建逻辑进行了以下更改。
+ S3 的默认凭证提供程序链不再包括匿名凭证。您必须使用 `AnonymousCredentialsProvider` 手动指定对 S3 的匿名访问。
+ 与默认客户端创建相关的以下环境变量有所不同。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/client-creation-defaults.html)
+ 与默认客户端创建相关的以下系统属性有所不同。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/client-creation-defaults.html)
+ 版本 2.x 不支持以下系统属性。
+     
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/client-creation-defaults.html)
+ 不再支持从自定义 `endpoints.json` 文件加载区域配置。

# 客户端配置
<a name="client-configuration"></a>

在 1.x 中，已通过在客户端或客户端生成器上设置 `ClientConfiguration` 实例修改了 SDK 客户端配置。在版本 2.x 中，已将客户端配置分为单独的配置类。利用单独的配置类，您可以为异步客户端与同步客户端配置不同的 HTTP 客户端，但仍使用相同的 `ClientOverrideConfiguration` 类。

**Example 版本 1.x 中的客户端配置**  

```
AmazonDynamoDBClientBuilder.standard()
.withClientConfiguration(clientConfiguration)
.build()
```

**Example 版本 2.x 中的同步客户端配置**  

```
ProxyConfiguration.Builder proxyConfig = ProxyConfiguration.builder();

ApacheHttpClient.Builder httpClientBuilder =
        ApacheHttpClient.builder()
                        .proxyConfiguration(proxyConfig.build());

ClientOverrideConfiguration.Builder overrideConfig =
        ClientOverrideConfiguration.builder();

DynamoDbClient client =
        DynamoDbClient.builder()
                      .httpClientBuilder(httpClientBuilder)
                      .overrideConfiguration(overrideConfig.build())
                      .build();
```

**Example 版本 2.x 中的异步客户端配置**  

```
NettyNioAsyncHttpClient.Builder httpClientBuilder =
        NettyNioAsyncHttpClient.builder();

ClientOverrideConfiguration.Builder overrideConfig =
        ClientOverrideConfiguration.builder();

ClientAsyncConfiguration.Builder asyncConfig =
        ClientAsyncConfiguration.builder();

DynamoDbAsyncClient client =
        DynamoDbAsyncClient.builder()
                           .httpClientBuilder(httpClientBuilder)
                           .overrideConfiguration(overrideConfig.build())
                           .asyncConfiguration(asyncConfig.build())
                           .build();
```

## HTTP 客户端
<a name="client-configuration-http"></a>

### 主要更改
<a name="client-configuration-http-notables"></a>
+ 在版本 2.x 中，您可以通过使用 `clientBuilder.httpClientBuilder` 指定实现来更改在运行时使用的 HTTP 客户端。
+ 使用 `clientBuilder.httpClient` 将 HTTP 客户端传递给服务客户端生成器时，如果服务客户端关闭，则默认情况下不会关闭 HTTP 客户端。这让您可以在服务客户端之间共享 HTTP 客户端。
+ 异步 HTTP 客户端现在使用非阻塞 IO。
+ 一些操作现在使用 HTTP/2 来提高性能。

### 更改设置
<a name="client-configuration-http-setting-diffs"></a>


| 设置 | 1.x | 2.x 同步，Apache | 2.x 异步，Netty | 
| --- | --- | --- | --- | 
|  |  <pre>ClientConfiguration clientConfig = <br />    new ClientConfiguration()</pre>  |  <pre>ApacheHttpClient.Builder httpClientBuilder = <br />    ApacheHttpClient.builder()</pre>  |  <pre>NettyNioAsyncHttpClient.Builder httpClientBuilder = <br />    NettyNioAsyncHttpClient.builder()</pre>  | 
| 最大连接数 |  <pre>clientConfig.setMaxConnections(...)<br />clientConfig.withMaxConnections(...)</pre>  |  <pre>httpClientBuilder.maxConnections(...)</pre>  |  <pre>httpClientBuilder.maxConcurrency(...)</pre>  | 
| 连接超时 |  <pre>clientConfig.setConnectionTimeout(...)<br />clientConfig.withConnectionTimeout(...)</pre>  |  <pre>httpClientBuilder.connectionTimeout(...)<br />httpClientBuilder.connectionAcquisitionTimeout(...)</pre>  |  <pre>httpClientBuilder.connectionTimeout(...)</pre>  | 
| 套接字超时 |  <pre>clientConfig.setSocketTimeout(...)<br />clientConfig.withSocketTimeout(...)</pre>  |  <pre>httpClientBuilder.socketTimeout(...)</pre>  |  <pre>httpClientBuilder.writeTimeout(...)<br />httpClientBuilder.readTimeout(...)</pre>  | 
| 连接 TTL |  <pre>clientConfig.setConnectionTTL(...)<br />clientConfig.withConnectionTTL(...)</pre>  |  <pre>httpClientBuilder.connectionTimeToLive(...)</pre>  |  <pre>httpClientBuilder.connectionTimeToLive(...)</pre>  | 
| 连接最大空闲时间 |  <pre>clientConfig.setConnectionMaxIdleMillis(...)<br />clientConfig.withConnectionMaxIdleMillis(...)</pre>  |  <pre>httpClientBuilder.connectionMaxIdleTime(...)</pre>  |  <pre>httpClientBuilder.connectionMaxIdleTime(...)</pre>  | 
| 处于非活动状态后进行验证 |  <pre>clientConfig.setValidateAfterInactivityMillis(...)<br />clientConfig.withValidateAfterInactivityMillis(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
| 本地地址 |  <pre>clientConfig.setLocalAddress(...)<br />clientConfig.withLocalAddress(...)</pre>  |  <pre>httpClientBuilder.localAddress(...)</pre>  | [不支持](https://github.com/aws/aws-sdk-java-v2/issues/857) | 
| 已启用 Expect-continue |  <pre>clientConfig.setUseExpectContinue(...)<br />clientConfig.withUseExpectContinue(...)</pre>  |  <pre>httpClientBuilder.expectContinueEnabled(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
| 连接收割者 |  <pre>clientConfig.setUseReaper(...)<br />clientConfig.withReaper(...)</pre>  |  <pre>httpClientBuilder.useIdleConnectionReaper(...)</pre>  |  <pre>httpClientBuilder.useIdleConnectionReaper(...)</pre>  | 
|  |  <pre>AmazonDynamoDBClientBuilder.standard()<br />    .withClientConfiguration(clientConfiguration)<br />    .build()</pre>  |  <pre>DynamoDbClient.builder()<br />    .httpClientBuilder(httpClientBuilder)<br />    .build()</pre>  |  <pre>DynamoDbAsyncClient.builder()<br />.httpClientBuilder(httpClientBuilder)<br />.build()</pre>  | 

## HTTP 客户端代理
<a name="client-configuration-http-proxy"></a>


| 设置 | 1.x | 2.x 同步，Apache | 2.x 异步，Netty | 
| --- | --- | --- | --- | 
|  |  <pre>ClientConfiguration clientConfig =<br />    new ClientConfiguration()</pre>  |  <pre>ProxyConfiguration.Builder proxyConfig =<br />    ProxyConfiguration.builder()</pre>  |  <pre>ProxyConfiguration.Builder proxyConfig =<br />    ProxyConfiguration.builder()</pre>  | 
| 代理主机 |  <pre>clientConfig.setProxyHost(...)<br />clientConfig.withProxyHost(...)</pre>  |  <pre>proxyConfig.endpoint(...)</pre>  |  <pre>proxyConfig.host(...)</pre>  | 
| 代理端口 |  <pre>clientConfig.setProxyPort(...)<br />clientConfig.withProxyPort(...)</pre>  |  <pre>proxyConfig.endpoint(...)</pre> [代理端口](http-configuration-apache.md#http-configuration-apache-proxy-conf-ex)嵌入在 `endpoint`  |  <pre>proxyConfig.port(...)</pre>  | 
| 代理用户名 |  <pre>clientConfig.setProxyUsername(...)<br />clientConfig.withProxyUsername(...)</pre>  |  <pre>proxyConfig.username(...)</pre>  |  <pre>proxyConfig.username(...)</pre>  | 
| 代理密码 |  <pre>clientConfig.setProxyPassword(...)<br />clientConfig.withProxyPassword(...)</pre>  |  <pre>proxyConfig.password(...)</pre>  |  <pre>proxyConfig.password(...)</pre>  | 
| 代理域 |  <pre>clientConfig.setProxyDomain(...)<br />clientConfig.withProxyDomain(...)</pre>  |  <pre>proxyConfig.ntlmDomain(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
| 代理工作站 |  <pre>clientConfig.setProxyWorkspace(...)<br />clientConfig.withProxyWorkstation(...)</pre>  |  <pre>proxyConfig.ntlmWorkstation(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
| 代理身份验证方法 |  <pre>clientConfig.setProxyAuthenticationMethods(...)<br />clientConfig.withProxyAuthenticationMethods(...)</pre>  |  [不支持](https://github.com/aws/aws-sdk-java-v2/issues/858)  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
| 预发式基本代理身份验证 |  <pre>clientConfig.setPreemptiveBasicProxyAuth(...)<br />clientConfig.withPreemptiveBasicProxyAuth(...)</pre>  |  <pre>proxyConfig.preemptiveBasicAuthenticationEnabled(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
| 非代理主机 |  <pre>clientConfig.setNonProxyHosts(...)<br />clientConfig.withNonProxyHosts(...)</pre>  |  <pre>proxyConfig.nonProxyHosts(...)</pre>  |  <pre>proxyConfig.nonProxyHosts(...)</pre>  | 
| 禁用套接字代理 |  <pre>clientConfig.setDisableSocketProxy(...)<br />clientConfig.withDisableSocketProxy(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
|  |  <pre>AmazonDynamoDBClientBuilder.standard()<br />    .withClientConfiguration(clientConfiguration)<br />    .build()</pre>  |  <pre>httpClientBuilder.proxyConfiguration(<br />    proxyConfig.build())</pre>  |  <pre>httpClientBuilder.proxyConfiguration(<br />    proxyConfig.build())</pre>  | 

## 客户端覆盖
<a name="client-override-config-diffs"></a>


| 设置 | 1.x | 2.x | 
| --- | --- | --- | 
|  |  <pre>ClientConfiguration clientConfig =<br />    new ClientConfiguration()</pre>  |  <pre>ClientOverrideConfiguration.Builder overrideConfig =<br />    ClientOverrideConfiguration.builder()</pre>  | 
| 用户代理前缀 |  <pre>clientConfig.setUserAgentPrefix(...)<br />clientConfig.withUserAgentPrefix(...)</pre>  |  <pre>overrideConfig.advancedOption(<br />    SdkAdvancedClientOption.USER_AGENT_PREFIX, ...)</pre>  | 
| 用户代理后缀 |  <pre>clientConfig.setUserAgentSuffix(...)<br />clientConfig.withUserAgentSuffix(...)</pre>  |  <pre>overrideConfig.advancedOption(<br />    SdkAdvancedClientOption.USER_AGENT_SUFFIX, ...)</pre>  | 
| 签署人 |  <pre>clientConfig.setSignerOverride(...)<br />clientConfig.withSignerOverride(...)</pre>  |  <pre>overrideConfig.advancedOption(<br />    SdkAdvancedClientOption.SIGNER, ...)</pre>  | 
| 其他标头 |  <pre>clientConfig.addHeader(...)<br />clientConfig.withHeader(...)</pre>  |  <pre>overrideConfig.putHeader(...)</pre>  | 
| 请求超时 |  <pre>clientConfig.setRequestTimeout(...)<br />clientConfig.withRequestTimeout(...)</pre>  |  <pre>overrideConfig.apiCallAttemptTimeout(...)</pre>  | 
| 客户端执行超时 |  <pre>clientConfig.setClientExecutionTimeout(...)<br />clientConfig.withClientExecutionTimeout(...)</pre>  |  <pre>overrideConfig.apiCallTimeout(...)</pre>  | 
| 使用 Gzip |  <pre>clientConfig.setUseGzip(...)<br />clientConfig.withGzip(...)</pre>  |  不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)）  | 
| 套接字缓冲区大小提示 |  <pre>clientConfig.setSocketBufferSizeHints(...)<br />clientConfig.withSocketBufferSizeHints(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
| 缓存响应元数据 |  <pre>clientConfig.setCacheResponseMetadata(...)<br />clientConfig.withCacheResponseMetadata(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
| 响应元数据缓存大小 |  <pre>clientConfig.setResponseMetadataCacheSize(...)<br />clientConfig.withResponseMetadataCacheSize(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
| DNS 解析程序 |  <pre>clientConfig.setDnsResolver(...)<br />clientConfig.withDnsResolver(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
| TCP keepalive |  <pre>clientConfig.setUseTcpKeepAlive(...)<br />clientConfig.withTcpKeepAlive(...)</pre>  |  此选项现在位于 HTTP 客户端配置中 <pre>- ApacheHttpClient.builder().tcpKeepAlive(true)<br />- NettyNioAsyncHttpClient.builder().tcpKeepAlive(true)</pre>  | 
| 安全随机 |  <pre>clientConfig.setSecureRandom(...)<br />clientConfig.withSecureRandom(...)</pre>  | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
|  |  <pre>AmazonDynamoDBClientBuilder.standard()<br />    .withClientConfiguration(clientConfiguration)<br />    .build()</pre>  |  <pre>DynamoDbClient.builder()<br />    .overrideConfiguration(overrideConfig.build())<br />    .build()</pre>  | 

## 客户端覆盖重试次数
<a name="client-override-retry-config-diffs"></a>


| 设置 | 1.x | 2.x | 
| --- | --- | --- | 
|  |  <pre>ClientConfiguration clientConfig =<br />    new ClientConfiguration()</pre>  |  <pre>ClientOverrideConfiguration.Builder overrideConfigBuilder = <br />    ClientOverrideConfiguration.builder();</pre>  | 
| 最大错误重试数 |  <pre>clientConfig.setMaxErrorRetry(...)<br />clientConfig.withMaxErrorRetry(...)</pre>  |  <pre>// Configure the default retry strategy.<br />overrideConfigBuilder.retryStrategy(b -> b.maxAttempts(...));</pre>  | 
| 使用带节流控制的重试次数 |  <pre>clientConfig.setUseThrottleRetries(...)<br />clientConfig.withUseThrottleRetries(...)</pre>  | [不支持](https://github.com/aws/aws-sdk-java-v2/issues/645) | 
| 节流前的最大连续重试次数 |  <pre>clientConfig.setMaxConsecutiveRetriesBeforeThrottling(...)<br />clientConfig.withMaxConsecutiveRetriesBeforeThrottling(...)</pre>  | [不支持](https://github.com/aws/aws-sdk-java-v2/issues/645) | 
|  |  <pre>AmazonDynamoDBClientBuilder.standard()<br />    .withClientConfiguration(clientConfiguration)<br />    .build()</pre>  |  <pre>DynamoDbClient.builder()<br />        .overrideConfiguration(overrideConfigBuilder.build())<br />        .build();<br /><br />// You also have the option to use a lambda expression to configure and<br />// build the 'ClientOverrideConfiguration.Builder'.<br />DynamoDbClient client = DynamoDbClient.builder()<br />        .overrideConfiguration(o -> o.retryStrategy(b -> b.maxAttempts(5)))<br />        .build();</pre>  | 

## 异步客户端
<a name="client-async-config-diffs"></a>


| 设置 | 1.x | 2.x | 
| --- | --- | --- | 
|  |  |  <pre>ClientAsyncConfiguration.Builder asyncConfig =<br />    ClientAsyncConfiguration.builder()</pre>  | 
| 执行程序 |  <pre>AmazonDynamoDBAsyncClientBuilder.standard()<br />    .withExecutorFactory(...)<br />    .build()</pre>  |  <pre>asyncConfig.advancedOption(<br />    SdkAdvancedAsyncClientOption.FUTURE_COMPLETION_EXECUTOR, ...)</pre>  | 
|  |  |  <pre>DynamoDbAsyncClient.builder()<br />    .asyncConfiguration(asyncConfig)<br />    .build()</pre>  | 

## 其他客户端更改
<a name="client-config-other-diffs"></a>

1.x 中的以下 `ClientConfiguration` 选项在 SDK 的 2.x 中已更改，没有直接等效项。


| 设置 | 1.x | 2.x 等效项 | 
| --- | --- | --- | 
| 协议 |  <pre>clientConfig.setProtocol(Protocol.HTTP)<br />clientConfig.withProtocol(Protocol.HTTP)</pre>  |  默认情况下，协议设置为 HTTPS。要修改设置，请在客户端生成器中指定协议设置为 HTTP 端点： <pre>clientBuilder.endpointOverride(<br />    URI.create("http://..."))</pre>  | 

# 凭证提供程序更改
<a name="migration-client-credentials"></a>

本部分提供了适用于 Java 的 AWS SDK 1.x 与 2.x 版之间的凭证提供程序类和方法名称更改的映射。

## 显著差异
<a name="client-credentials"></a>
+ 在版本 2.x 中，默认凭证提供程序会在加载环境变量之前先加载系统属性。有关更多信息，请参阅[使用凭证](credentials.md)。
+ 构造函数方法已被替换为 `create` 或 `builder` 方法。  
**Example**  

  ```
  DefaultCredentialsProvider.create();
  ```
+ 默认情况下，不再设置异步刷新。您必须使用凭证提供程序的 `builder` 指定它。  
**Example**  

  ```
  ContainerCredentialsProvider provider = ContainerCredentialsProvider.builder()
          		.asyncCredentialUpdateEnabled(true)
          		.build();
  ```
+ 您可以使用 `ProfileCredentialsProvider.builder()` 指定自定义配置文件的路径。  
**Example**  

  ```
  ProfileCredentialsProvider profile = ProfileCredentialsProvider.builder()
          		.profileFile(ProfileFile.builder().content(Paths.get("myProfileFile.file")).build())
          		.build();
  ```
+ 配置文件格式已更改，以更贴近于 AWS CLI。有关详细信息，请参阅《AWS Command Line Interface 用户指南》**中的[配置 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html)。

## 版本 1.x 与 2.x 之间的凭证提供程序更改映射
<a name="credentials-changes-mapping"></a>

### `AWSCredentialsProvider`
<a name="credentials-provider-changes-AWSCredentialsProvider"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.AWSCredentialsProvider | software.amazon.awssdk.auth.credentials.AwsCredentialsProvider | 
| 方法名称 | getCredentials | resolveCredentials | 
| 不受支持的方法 | refresh | 不支持 | 

### `DefaultAWSCredentialsProviderChain`
<a name="credentials-provider-changes-DefaultAWSCredentialsProviderChain"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.DefaultAWSCredentialsProviderChain | software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider | 
| 创建 | new DefaultAWSCredentialsProviderChain | DefaultCredentialsProvider.create | 
| 不受支持的方法 | getInstance | 不支持 | 
| 外部设置的优先顺序 |  环境变量在系统属性之前  |  系统属性在环境变量之前  | 

### `AWSStaticCredentialsProvider`
<a name="credentials-provider-changes-AWSStaticCredentialsProvider"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.AWSStaticCredentialsProvider | software.amazon.awssdk.auth.credentials.StaticCredentialsProvider | 
| 创建 | new AWSStaticCredentialsProvider | StaticCredentialsProvider.create | 

### `EnvironmentVariableCredentialsProvider`
<a name="credentials-provider-changes-EnvironmentVariableCredentialsProvider"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.EnvironmentVariableCredentialsProvider | software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider | 
| 创建 | new EnvironmentVariableCredentialsProvider | EnvironmentVariableCredentialsProvider.create | 
| 环境变量名称 | AWS\$1ACCESS\$1KEY | AWS\$1ACCESS\$1KEY\$1ID | 
|  | AWS\$1SECRET\$1KEY | AWS\$1SECRET\$1ACCESS\$1KEY | 

### `SystemPropertiesCredentialsProvider`
<a name="credentials-provider-changes-SystemPropertiesCredentialsProvider"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.SystemPropertiesCredentialsProvider | software.amazon.awssdk.auth.credentials.SystemPropertyCredentialsProvider | 
| 创建 | new SystemPropertiesCredentialsProvider | SystemPropertiesCredentialsProvider.create | 
| 系统属性名称 | aws.secretKey | aws.secretAccessKey | 

### `ProfileCredentialsProvider`
<a name="credentials-provider-changes-ProfileCredentialsProvider"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.profile.ProfileCredentialsProvider | software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider | 
| 创建 | new ProfileCredentialsProvider | ProfileCredentialsProvider.create | 
| 自定义配置文件的位置 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/migration-client-credentials.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/migration-client-credentials.html)  | 

### `ContainerCredentialsProvider`
<a name="credentials-provider-changes-ContainerCredentialsProvider"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.ContainerCredentialsProvider | software.amazon.awssdk.auth.credentials.ContainerCredentialsProvider | 
| 创建 | new ContainerCredentialsProvider | ContainerCredentialsProvider.create | 
| 指定异步刷新 | 不支持 | 默认行为 | 

### `InstanceProfileCredentialsProvider`
<a name="credentials-provider-changes-InstanceProfileCredentialsProvider"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.InstanceProfileCredentialsProvider | software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider | 
| 创建 | new InstanceProfileCredentialsProvider | InstanceProfileCredentialsProvider.create | 
| 指定异步刷新 | new InstanceProfileCredentialsProvider(true) |  `InstanceProfileCredentialProvider.builder().asyncCredentialUpdateEnabled(true).build()`  | 
| 系统属性名称 | com.amazonaws.sdk.disableEc2Metadata | aws.disableEc2Metadata | 
|  | com.amazonaws.sdk.ec2MetadataServiceEndpointOverride | aws.ec2MetadataServiceEndpoint | 

### `STSAssumeRoleSessionCredentialsProvider`
<a name="credentials-provider-changes-STSAssumeRoleSessionCredentialsProvider"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider | software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider | 
| 创建 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/migration-client-credentials.html)  | StsAssumeRoleCredentialsProvider.builder | 
| 异步刷新 | 默认行为 | 默认行为 | 
| 配置 | new STSAssumeRoleSessionCredentialsProvider.Builder | 配置 StsClient 和 AssumeRoleRequest 请求 | 

### `STSSessionCredentialsProvider`
<a name="credentials-provider-changes-STSSessionCredentialsProvider"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.STSSessionCredentialsProvider | software.amazon.awssdk.services.sts.auth.StsGetSessionTokenCredentialsProvider | 
| 创建 |  `new STSSessionCredentialsProvider`  | StsGetSessionTokenCredentialsProvider.builder | 
| 异步刷新 | 默认行为 | StsGetSessionTokenCredentialsProvider.builder | 
| 配置 | 构造函数参数 | 在生成器中配置 StsClient 和 GetSessionTokenRequest 请求 | 

### `WebIdentityFederationSessionCredentialsProvider`
<a name="credentials-provider-changes-WebIdentityFederationSessionCredentialsProvider"></a>


| 更改类别 | 1.x | 2.x | 
| --- | --- | --- | 
| 软件包/类名称 | com.amazonaws.auth.WebIdentityFederationSessionCredentialsProvider | software.amazon.awssdk.services.sts.auth.StsAssumeRoleWithWebIdentityCredentialsProvider | 
| 创建 |  `new WebIdentityFederationSessionCredentialsProvider`  | StsAssumeRoleWithWebIdentityCredentialsProvider.builder | 
| 异步刷新 | 默认行为 | StsAssumeRoleWithWebIdentityCredentialsProvider.builder | 
| 配置 | 构造函数参数 | 在生成器中配置 StsClient 和 AssumeRoleWithWebIdentityRequest 请求 | 

### 已替换的类
<a name="credentials-provider-changes-Replacements"></a>


| 1.x 类 | 2.x 替换类 | 
| --- | --- | 
| com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper | software.amazon.awssdk.auth.credentials.ContainerCredentialsProvider 和 software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider | 
| com.amazonaws.services.s3.S3CredentialsProviderChain | software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider 和 software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider | 

### 已移除的类
<a name="credentials-provider-changes-Removed"></a>


| 1.x 类 | 
| --- | 
| com.amazonaws.auth.ClasspathPropertiesFileCredentialsProvider | 
| com.amazonaws.auth.PropertiesFileCredentialsProvider | 

# 区域更改
<a name="migration-client-region"></a>

本部分介绍了适用于 Java 的 AWS SDK 2.x 中针对 `Region` 和 `Regions` 类的使用实施的更改。

## 区域配置
<a name="region-configuration"></a>
+ 一些 AWS 服务没有特定于区域的端点。在使用这些服务时，您必须将区域设置为 `Region.AWS_GLOBAL` 或 `Region.AWS_CN_GLOBAL`。  
**Example**  

  ```
  Region region = Region.AWS_GLOBAL;
  ```
+  `com.amazonaws.regions.Regions` 和 `com.amazonaws.regions.Region` 类现在合并成一个类 `software.amazon.awssdk.regions.Region`。

## 方法和类名映射
<a name="region-method-mapping"></a>

下表列出了适用于 Java 的 AWS SDK 的 1.x 与 2.x 版之间的区域相关类的映射。您可以使用 `of()` 方法创建这些类的实例。

**Example**  

```
RegionMetadata regionMetadata = RegionMetadata.of(Region.US_EAST_1);
```


**1.x Regions 类方法更改**  

| 1.x | 2.x | 
| --- | --- | 
|  `Regions.fromName`  |  `Region.of`  | 
|  `Regions.getName`  |  `Region.id`  | 
|  `Regions.getDescription`  |  `Region.metadata().description()`  | 
|  `Regions.getCurrentRegion`  |  不支持  | 
|  `Regions.DEFAULT_REGION`  |  不支持  | 
|  `Regions.name`  |  `Region.id`  | 


**1.x Region 类方法更改**  

| 1.x | 2.x | 
| --- | --- | 
|  `Region.getName`  |  `Region.id`  | 
|  `Region.hasHttpsEndpoint`  |  不支持  | 
|  `Region.hasHttpEndpoint`  |  不支持  | 
|  `Region.getAvailableEndpoints`  |  不支持  | 
|  `Region.createClient`  |  不支持  | 


**RegionMetadata 类方法更改**  

| 1.x | 2.x | 
| --- | --- | 
|  `RegionMetadata.getName`  |  `RegionMetadata.name`  | 
|  `RegionMetadata.getDomain`  |  `RegionMetadata.domain`  | 
|  `RegionMetadata.getPartition`  |  `RegionMetadata.partition`  | 


**ServiceMetadata 类方法更改**  

| 1.x | 2.x | 
| --- | --- | 
|  `Region.getServiceEndpoint`  |  `ServiceMetadata.endpointFor(Region)`  | 
|  `Region.isServiceSupported`  |  `ServiceMetadata.regions().contains(Region)`  | 

# 操作、请求和响应更改
<a name="migration-operation-requests-responses"></a>

在适用于 Java 的 SDK 版本 2 中，请求会传递给客户端操作。例如 `DynamoDbClient's` `PutItemRequest` 传递给 `DynamoDbClient.putItem` 操作。这些操作会返回来自的响应 AWS 服务，例如`PutItemResponse`。

适用于 Java 的 SDK 版本 2 与版本 1 相比有以下变化。
+ 现在，具有多个响应页面的操作使用 `Paginator` 方法来自动遍历响应中的所有项目。
+ 您不能改变请求和响应。
+ 必须使用静态生成器方法而不是构造函数来创建请求和响应。例如，版本 1 的 `new PutItemRequest().withTableName(...)` 现在为 `PutItemRequest.builder().tableName(...).build()`。
+ 操作支持使用简写方式来创建请求：`dynamoDbClient.putItem(request -> request.tableName(...))`。

以下各节说明版本 1 和版本 2 之间的具体更改。有些参数类型更改可以使用[迁移工具](migration-tool.md)自动转换，而其他更改则需要手动更新代码。

# Date 参数更改
<a name="migration-date-parameters"></a>

在版本 1 中，许多操作在处理基于时间的参数时都接受 `java.util.Date` 对象。在版本 2 中，这些操作改为使用 `java.time.Instant` 对象。

您可以使用[迁移工具](migration-tool.md)自动转换 `Date` 参数，也可以通过在 `Date` 对象上调用 `toInstant()` 方法来手动转换参数。

**Example - 在版本 1 中，使用 Date 指定过期日期来生成预签名 URL**  

```
// Generate a presigned URL that expires at a specific date
Date expiration = new Date(System.currentTimeMillis() + 3600000); // 1 hour from now
URL presignedUrl = s3Client.generatePresignedUrl(bucketName, keyName, expiration);
```

**Example - 在版本 2 中，使用 Instant 指定过期时间来生成预签名 URL**  

```
// Generate a presigned URL that expires at a specific instant
Date expiration = new Date(System.currentTimeMillis() + 3600000); // 1 hour from now
PresignedGetObjectRequest presignedRequest = presigner.presignGetObject(
    GetObjectPresignRequest.builder()
        .getObjectRequest(GetObjectRequest.builder()
            .bucket(bucketName)
            .key(keyName)
            .build())
        .signatureDuration(Duration.between(Instant.now(), expiration.toInstant()))
        .build());
```

# 二进制数据处理更改
<a name="migration-binary-data"></a>

在版本 1 中，使用 `ByteBuffer` 对象直接处理二进制数据。在版本 2 中，SDK 使用 `SdkBytes` 对象，该对象提供一种更便捷、类型更安全的方式来处理二进制数据。

您可以使用[迁移工具](migration-tool.md)自动将 `SdkBytes` 转换为 `ByteBuffer`，也可以通过在返回的 `SdkBytes` 对象上调用 `asByteBuffer()` 来手动转换参数。

**Example - 在版本 1 中从消息属性获取二进制数据**  

```
// Get binary data from a message attribute
MessageAttributeValue messageAttributeValue = new MessageAttributeValue();
ByteBuffer binaryValue = messageAttributeValue.getBinaryValue();
String binaryString = new String(messageAttributeValue.getBinaryValue().array());
```

**Example - 在版本 2 中从消息属性获取二进制数据**  

```
// Get binary data from a message attribute
MessageAttributeValue messageAttributeValue = MessageAttributeValue.builder().build();
ByteBuffer binaryValue = messageAttributeValue.binaryValue().asByteBuffer();
String binaryString = new String(messageAttributeValue.binaryValue().asByteBuffer().array());
```

# 超时参数更改
<a name="migration-timeout-parameters"></a>

在版本 1 中，超时值指定为代表毫秒的整数值。在版本 2 中，超时参数使用 `java.time.Duration` 对象来获得更好的类型安全性和清晰度。

您可以使用[迁移工具](migration-tool.md)自动转换数值超时值，也可以通过使用适当的 `Duration` 工厂方法来包装数值，从而手动转换这些值。

**Example - 在版本 1 中设置请求超时**  

```
// Set request timeout in milliseconds
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setRequestTimeout(5000); // 5 seconds
```

**Example - 在版本 2 中设置请求超时**  

```
// Set request timeout using Duration
ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.setRequestTimeout(Duration.ofMillis(5000)); // 5 seconds

// Or more clearly:
clientConfiguration.setRequestTimeout(Duration.ofSeconds(5)); // 5 seconds
```

您可以使用以下 `Duration` 工厂方法设置超时值：
+ `Duration.ofMillis(long millis)` - 用于毫秒值。
+ `Duration.ofSeconds(long seconds)` - 用于秒值。
+ `Duration.ofMinutes(long minutes)` - 用于分钟值。

# 1.x 和 2.x 之间的流媒体操作差异 适用于 Java 的 AWS SDK
<a name="migration-streaming-ops"></a>

在 SDK 的 2.x 版本 I/O 中，流式传输操作（例如 Amazon S3 `getObject` 和`putObject`方法）支持非阻塞功能。因此，请求和响应模型对象不再获取 `InputStream` 作为参数。相反，对于异步请求，请求对象接受 `RequestBody`（这是一个字节流）。异步等效项接受 `AsyncRequestBody`。

**Example 1.x 中的 Amazon S3 `putObject` 操作**  

```
s3client.putObject(BUCKET, KEY, new File(file_path));
```

**Example 2.x 中的 Amazon S3 `putObject` 操作**  

```
s3client.putObject(PutObjectRequest.builder()
                                 .bucket(BUCKET)
                                 .key(KEY)
                                 .build(),
                 RequestBody.of(Paths.get("myfile.in")));
```

在 V2 中，流式响应对象接受 `ResponseTransformer`（对于同步客户端）和 `AsyncResponseTransformer`（对于异步客户端）。

**Example 1.x 中的 Amazon S3 `getObject` 操作**  

```
S3Object o = s3.getObject(bucket, key);
S3ObjectInputStream s3is = o.getObjectContent();
FileOutputStream fos = new FileOutputStream(new File(key));
```

**Example 2.x 中的 Amazon S3 `getObject` 操作**  

```
s3client.getObject(GetObjectRequest.builder().bucket(bucket).key(key).build(),
		ResponseTransformer.toFile(Paths.get("key")));
```

在适用于 Java 的 SDK 2.x 中，流式响应操作使用 `AsBytes` 方法将响应加载到内存中，并简化了内存中的常见类型转换。

# 1.x 和 2.x 之间的序列化差异 适用于 Java 的 AWS SDK
<a name="migration-serialization-changes"></a>

## 列出请求对象的参数差异
<a name="serialization-diffs-list-obj-to-req-param"></a>

SDK for Java v1.x 和 v2.x 的不同之处在于它们如何序列化列表对象以请求参数。

SDK for Java 1.x 不会序列化空列表，而 SDK for Java 2.x 会将空列表序列化为空参数。

例如，假设一项服务具有 `SampleOperation`，会接收 `SampleRequest`。`SampleRequest` 接受两个参数，字符串类型 `str1` 和列表类型 `listParam`，如以下示例所示。

**Example 1.x 中 `SampleOperation` 的示例**  

```
SampleRequest v1Request = new SampleRequest()
    .withStr1("TestName");

sampleServiceV1Client.sampleOperation(v1Request);
```
线级日志记录显示 `listParam` 参数未序列化。  

```
Action=SampleOperation&Version=2011-01-01&str1=TestName
```

**Example 2.x 中 `SampleOperation` 的示例**  

```
sampleServiceV2Client.sampleOperation(b -> b
    .str1("TestName"));
```
线级日志记录显示 `listParam` 参数进行了序列化，没有任何值。  

```
Action=SampleOperation&Version=2011-01-01&str1=TestName&listParam=
```

## POJOs 在 V1 中与 V2 中的构建器相比
<a name="serialization-json-objects"></a>

由于适用于 Java 的 SDK V1 使用可变的 POJO 类，因此序列化和反序列化库（例如 [Jackson](https://github.com/FasterXML/jackson-docs)）可以直接使用模型对象。

相比之下，适用于 Java 的 SDK V2 使用不可变的模型对象。必须使用中间生成器来执行反序列化/序列化。

以下示例显示了 V1 的 `headBucket` API 调用和使用 Jackson 的 V2 调用之间的 de/serializing 区别。`ObjectMapper`

```
    public void sendRequest() throws IOException {
        final String bucketName = "amzn-s3-demo-bucket";
        final ObjectMapper mapper = new ObjectMapper();

        // V1 uses POJOs to serialize and deserialize.
        final AmazonS3 v1S3Client = AmazonS3ClientBuilder.defaultClient();
        HeadBucketResult resultV1 = v1S3Client.headBucket(
            new HeadBucketRequest(bucketName));

        String v1Serialized = mapper.writeValueAsString(resultV1);

        HeadBucketResult deserializedV1 = mapper.readValue(v1Serialized, HeadBucketResult.class);
        
        // V2 uses builders to serialize and deserialize.
        S3Client v2S3Client = S3Client.create();
        HeadBucketResponse v2Response = v2S3Client.headBucket(
            b -> b.bucket(bucketName));

        String v2Serialized = mapper.writeValueAsString(
            v2Response.toBuilder());

        HeadBucketResponse v2Deserialized = mapper.readValue(
            v2Serialized, HeadBucketResponse.serializableBuilderClass())
            .build();
    }
```

# 1.x 和 2.x 之间的反序列化差异 适用于 Java 的 AWS SDK
<a name="migration-deserialization-changes"></a>

## V2 中的空集合与 V1 中的 `nulls` 相比
<a name="deserialization-diffs-list-obj-to-req-param"></a>

适用于 Java 的 SDK v1.x 和 v2.x 在反序列化包含空列表或映射的 JSON 响应时行为不同。

当 SDK 收到缺失属性的响应时，该响应在模型中定义为列表或映射，V1 会将缺失的属性反序列化为 `null`，而 V2 则将属性反序列化为不可变的空集合对象。

例如，考虑从 DynamoDB 客户端为 `describeTable` 方法返回的响应。以下示例方法包含一个 V2 DynamoDB 客户端和一个 V1 DynamoDB 客户端，它们都在没有全局二级索引的表上执行 `describeTable` 方法

**Example 在响应中缺失、但在模型中定义为列表类型的属性的反序列化**  

```
public void deserializationDiffs(){

    DescribeTableResponse v2Response = dynamoDbClientV2.describeTable(builder -> builder.tableName(TABLE_NAME));
    // V2 provides has* methods on model objects for list/map members. No null check needed.
    LOGGER.info( String.valueOf(v2Response.table().hasGlobalSecondaryIndexes()) );
    LOGGER.info( String.valueOf(v2Response.table().globalSecondaryIndexes().isEmpty()) );
    // V2 deserialize to an empty collection.
    LOGGER.info(v2Response.table().globalSecondaryIndexes().toString());

    // V1 deserialize to null.
    DescribeTableResult v1Result = dynamoDbClientV1.describeTable(new DescribeTableRequest(TABLE_NAME));
    if (v1Result.getTable().getGlobalSecondaryIndexes() != null){
        LOGGER.info(v1Result.getTable().getGlobalSecondaryIndexes().toString());
    } else {
        LOGGER.info("The list of global secondary indexes returned by the V1 call is <null>");
    }
}
```
以下内容展示了记录的日志输出：  

```
INFO  org.example.DeserializationDifferences:45 - false
INFO  org.example.DeserializationDifferences:46 - true
INFO  org.example.DeserializationDifferences:48 - []
INFO  org.example.DeserializationDifferences:55 - The list of global secondary indexes returned by the V1 call is <null>
```

Java SDK 2.x 采用了一种惯用的方法，将空列表和映射反序列化为不可变的空集合，而不是返回 `null`，从而有助于编写更安全、更简洁的代码。在 V2 中，您可以使用 `has*` 方法（例如，前面的示例中所示的 `hasGlobalSecondaryIndexes`）检查服务是否返回了在模型中定义为列表或映射的属性。

使用这种方法，就不需要进行明确的 `null` 检查，并且符合现代 Java 中处理“缺失”或“空”数据结构的最佳实践。

### 完整示例
<a name="full-example-deserialization"></a>

```
package org.example;

import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.DescribeTableRequest;
import com.amazonaws.services.dynamodbv2.model.DescribeTableResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.BillingMode;
import software.amazon.awssdk.services.dynamodb.model.DescribeTableResponse;
import software.amazon.awssdk.services.dynamodb.model.KeyType;
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType;

import java.util.UUID;

public class DeserializationDifferences {
    private static final Logger LOGGER = LoggerFactory.getLogger(DeserializationDifferences.class);
    private static final String TABLE_NAME = "DeserializationTable-" + UUID.randomUUID();
    DynamoDbClient dynamoDbClientV2 = DynamoDbClient.create();
    AmazonDynamoDB dynamoDbClientV1 = AmazonDynamoDBClientBuilder.standard().withRegion(Regions.US_EAST_1).build();

    public static void main(String[] args) {

        DeserializationDifferences difference = new DeserializationDifferences();
        difference.createTable();
        difference.deserializationDiffs();
        difference.deleteTable();
    }

    public void createTable(){
        dynamoDbClientV2.createTable(b -> b
                .billingMode(BillingMode.PAY_PER_REQUEST)
                .tableName(TABLE_NAME)
                .keySchema(b1 -> b1.attributeName("Id").keyType(KeyType.HASH))
                .attributeDefinitions(b2 -> b2.attributeName("Id").attributeType(ScalarAttributeType.S)));
        dynamoDbClientV2.waiter().waitUntilTableExists(b -> b.tableName(TABLE_NAME));
    }

    public void deserializationDiffs(){

        DescribeTableResponse v2Response = dynamoDbClientV2.describeTable(builder -> builder.tableName(TABLE_NAME));
        // V2 provides has* methods on model objects for list/map members. No null check needed.
        LOGGER.info( String.valueOf(v2Response.table().hasGlobalSecondaryIndexes()) );
        LOGGER.info( String.valueOf(v2Response.table().globalSecondaryIndexes().isEmpty()) );
        // V2 deserialize to an empty collection.
        LOGGER.info(v2Response.table().globalSecondaryIndexes().toString());

        // V1 deserialize to null.
        DescribeTableResult v1Result = dynamoDbClientV1.describeTable(new DescribeTableRequest(TABLE_NAME));
        if (v1Result.getTable().getGlobalSecondaryIndexes() != null){
            LOGGER.info(v1Result.getTable().getGlobalSecondaryIndexes().toString());
        } else {
            LOGGER.info("The list of global secondary indexes returned by the V1 call is <null>");
        }
    }

    public void deleteTable(){
        dynamoDbClientV2.deleteTable(b -> b.tableName(TABLE_NAME));
        dynamoDbClientV2.waiter().waitUntilTableNotExists(b -> b.tableName(TABLE_NAME));
    }
}
```

来自 V1 和 V2 客户端的 `describeTable` 方法的 JSON 响应不包含 `GlobalSecondaryIndexes` 属性：

```
{
  "Table": {
    "AttributeDefinitions": [
      {
        "AttributeName": "Id",
        "AttributeType": "S"
      }
    ],
    "BillingModeSummary": {
      "BillingMode": "PAY_PER_REQUEST",
      "LastUpdateToPayPerRequestDateTime": ...
    },
    "CreationDateTime": ...,
    "DeletionProtectionEnabled": false,
    "ItemCount": 0,
    "KeySchema": [
      {
        "AttributeName": "Id",
        "KeyType": "HASH"
      }
    ],
    "ProvisionedThroughput": {
      "NumberOfDecreasesToday": 0,
      "ReadCapacityUnits": 0,
      "WriteCapacityUnits": 0 
    },
    "TableArn": "arn:aws:dynamodb:us-east-1:11111111111:table/DeserializationTable-...",
    "TableId": "...",
    "TableName": "DeserializationTable-...",
    "TableSizeBytes": 0,
    "TableStatus": "ACTIVE",
    "TableThroughputModeSummary": {
      "LastUpdateToPayPerRequestDateTime": ...,
      "TableThroughputMode": "PAY_PER_REQUEST"
    },
    "WarmThroughput": {
      "ReadUnitsPerSecond": 12000,
      "Status": "ACTIVE",
      "WriteUnitsPerSecond": 4000
    }
  }
}
```

# Exception 更改
<a name="migration-exception-changes"></a>

异常类名及其结构和关系已更改。`software.amazon.awssdk.core.exception.SdkException` 是新的基础 `Exception` 类，所有其他异常从该类进行扩展。

此表列出了 Exception 类名更改的映射。


| 1.x | 2.x | 
| --- | --- | 
|   `com.amazonaws.SdkBaseException` `com.amazonaws.AmazonClientException`   |   `software.amazon.awssdk.core.exception.SdkException`   | 
|   `com.amazonaws.SdkClientException`   |   `software.amazon.awssdk.core.exception.SdkClientException`   | 
|   `com.amazonaws.AmazonServiceException`   |   `software.amazon.awssdk.awscore.exception.AwsServiceException`   | 

下表列出了版本 1.x 与 2.x 之间 Exception 类方法的映射。


| 1.x | 2.x | 
| --- | --- | 
|   `AmazonServiceException.getRequestId`   |   `SdkServiceException.requestId`   | 
|   `AmazonServiceException.getServiceName`   |   `AwsServiceException.awsErrorDetails().serviceName`   | 
|   `AmazonServiceException.getErrorCode`   |   `AwsServiceException.awsErrorDetails().errorCode`   | 
|   `AmazonServiceException.getErrorMessage`   |   `AwsServiceException.awsErrorDetails().errorMessage`   | 
|   `AmazonServiceException.getStatusCode`   |   `AwsServiceException.awsErrorDetails().sdkHttpResponse().statusCode`   | 
|   `AmazonServiceException.getHttpHeaders`   |   `AwsServiceException.awsErrorDetails().sdkHttpResponse().headers`   | 
|   `AmazonServiceException.rawResponse`   |   `AwsServiceException.awsErrorDetails().rawResponse`   | 

# 特定于服务的更改
<a name="migration-service-changes"></a>

## Amazon S3 更改
<a name="s3-operations-name"></a>

适用于 Java 的 SDK 2.x 默认禁用匿名访问。因此，您必须使用 `AnonymousCredentialsProvider` 启用匿名访问。

### 操作名称更改
<a name="s3-op-name-changes"></a>

Amazon S3 客户端的许多操作名称在适用于 Java 的 AWS SDK 2.x 中已更改。在版本 1.x 中，不直接从服务 API 生成 Amazon S3 客户端。这会导致开发工具包操作与服务 API 之间的不一致。在版本 2.x 中，我们现在生成 Amazon S3 客户端以提高与服务 API 的一致性。

下表显示两个版本中的操作名称。


**Amazon S3 操作名称**  

| 1.x | 2.x | 
| --- | --- | 
| abortMultipartUpload | abortMultipartUpload | 
| changeObjectStorageClass  | copyObject | 
| completeMultipartUpload  | completeMultipartUpload | 
| copyObject | copyObject | 
| copyPart | uploadPartCopy | 
| createBucket | createBucket | 
| deleteBucket | deleteBucket | 
| deleteBucketAnalyticsConfiguration | deleteBucketAnalyticsConfiguration | 
| deleteBucketCrossOriginConfiguration | deleteBucketCors | 
| deleteBucketEncryption | deleteBucketEncryption | 
| deleteBucketInventoryConfiguration | deleteBucketInventoryConfiguration | 
| deleteBucketLifecycleConfiguration | deleteBucketLifecycle | 
| deleteBucketMetricsConfiguration | deleteBucketMetricsConfiguration | 
| deleteBucketPolicy | deleteBucketPolicy | 
| deleteBucketReplicationConfiguration | deleteBucketReplication | 
| deleteBucketTaggingConfiguration | deleteBucketTagging | 
| deleteBucketWebsiteConfiguration | deleteBucketWebsite | 
| deleteObject | deleteObject | 
| deleteObjectTagging | deleteObjectTagging | 
| deleteObjects | deleteObjects | 
| deleteVersion | deleteObject | 
| disableRequesterPays | putBucketRequestPayment | 
| doesBucketExist | headBucket | 
| doesBucketExistV2 | headBucket | 
| doesObjectExist | headObject | 
| enableRequesterPays | putBucketRequestPayment | 
| generatePresignedUrl | [S3Presigner](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/presigner/S3Presigner.html) | 
| getBucketAccelerateConfiguration | getBucketAccelerateConfiguration | 
| getBucketAcl | getBucketAcl | 
| getBucketAnalyticsConfiguration | getBucketAnalyticsConfiguration | 
| getBucketCrossOriginConfiguration | getBucketCors | 
| getBucketEncryption | getBucketEncryption | 
| getBucketInventoryConfiguration | getBucketInventoryConfiguration | 
| getBucketLifecycleConfiguration | getBucketLifecycle 或者getBucketLifecycleConfiguration | 
| getBucketLocation | getBucketLocation | 
| getBucketLoggingConfiguration | getBucketLogging | 
| getBucketMetricsConfiguration | getBucketMetricsConfiguration | 
| getBucketNotificationConfiguration | getBucketNotification 或者getBucketNotificationConfiguration | 
| getBucketPolicy | getBucketPolicy | 
| getBucketReplicationConfiguration | getBucketReplication | 
| getBucketTaggingConfiguration | getBucketTagging | 
| getBucketVersioningConfiguration | getBucketVersioning | 
| getBucketWebsiteConfiguration | getBucketWebsite | 
| getObject | getObject | 
| getObjectAcl | getObjectAcl | 
| getObjectAsString | getObjectAsBytes().asUtf8String | 
| getObjectMetadata | headObject | 
| getObjectTagging | getObjectTagging | 
| getResourceUrl | [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Utilities.html#getUrl(java.util.function.Consumer)](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Utilities.html#getUrl(java.util.function.Consumer)) | 
| getS3AccountOwner | listBuckets | 
| getUrl | [S3Utilities\$1getUrl](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Utilities.html#getUrl(java.util.function.Consumer)) | 
| headBucket | headBucket | 
| initiateMultipartUpload | createMultipartUpload | 
| isRequesterPaysEnabled | getBucketRequestPayment | 
| listBucketAnalyticsConfigurations | listBucketAnalyticsConfigurations | 
| listBucketInventoryConfigurations | listBucketInventoryConfigurations | 
| listBucketMetricsConfigurations | listBucketMetricsConfigurations | 
| listBuckets | listBuckets | 
| listMultipartUploads | listMultipartUploads | 
| listNextBatchOfObjects | listObjectsV2Paginator | 
| listNextBatchOfVersions | listObjectVersionsPaginator | 
| listObjects | listObjects | 
| listObjectsV2 | listObjectsV2 | 
| listParts | listParts | 
| listVersions | listObjectVersions | 
| putObject | putObject | 
| restoreObject | restoreObject | 
| restoreObjectV2 | restoreObject | 
| selectObjectContent | selectObjectContent | 
| setBucketAccelerateConfiguration | putBucketAccelerateConfiguration | 
| setBucketAcl | putBucketAcl | 
| setBucketAnalyticsConfiguration | putBucketAnalyticsConfiguration | 
| setBucketCrossOriginConfiguration | putBucketCors | 
| setBucketEncryption | putBucketEncryption | 
| setBucketInventoryConfiguration | putBucketInventoryConfiguration | 
| setBucketLifecycleConfiguration | putBucketLifecycle 或者putBucketLifecycleConfiguration | 
| setBucketLoggingConfiguration | putBucketLogging | 
| setBucketMetricsConfiguration | putBucketMetricsConfiguration | 
| setBucketNotificationConfiguration | putBucketNotification 或者putBucketNotificationConfiguration | 
| setBucketPolicy | putBucketPolicy | 
| setBucketReplicationConfiguration | putBucketReplication | 
| setBucketTaggingConfiguration | putBucketTagging | 
| setBucketVersioningConfiguration | putBucketVersioning | 
| setBucketWebsiteConfiguration | putBucketWebsite | 
| setObjectAcl | putObjectAcl | 
| setObjectRedirectLocation | copyObject | 
| setObjectTagging | putObjectTagging | 
| uploadPart | uploadPart | 

## Amazon SNS 更改
<a name="sns-changes"></a>

除配置为可访问的区域外，SNS 客户端无法再访问其他区域中的 SNS 主题。

## Amazon SQS 更改
<a name="sqs-changes"></a>

除配置为可访问的区域外，SQS 客户端无法再访问其他区域中的 SQS 队列。

## Amazon RDS 更改
<a name="rds-changes"></a>

适用于 Java 的 SDK 2.x 使用 `RdsUtilities#generateAuthenticationToken` 代替 1.x 中的类 `RdsIamAuthTokenGenerator`。

# 使用 Amazon S3 时从第 1 版改为第 2 版 适用于 Java 的 AWS SDK
<a name="migration-s3"></a>

对 S3 客户端进行了重大更改，包括新的包结构、更新的类名和修订的方法签名。 AWS SDK for Java 2.x 虽然使用[迁移工具](migration-tool.md)可以自动将许多方法从 V1 迁移到 V2，但有些方法需要手动迁移，例如 `listNextBatchOfObjects` 和 `selectObjectContent`。此外，V2 用新的实现取代了某些 V1 类（例如 `AccessControlList` 和 `CannedAccessControlList`）。

**Topics**
+ [版本 1 和版本 2 之间的 S3 客户端区别 适用于 Java 的 AWS SDK](migration-s3-client.md)
+ [将传输管理器从版本 1 迁移到版本 2 适用于 Java 的 AWS SDK](migration-s3-transfer-manager.md)
+ [在解析 Amazon S3 时 URIs 从版本 1 到版本 2 的变化](migration-s3-uri-parser.md)
+ [S3 事件通知 API 从版本 1 到版本 2 的更改](migration-s3-event-notification.md)

# 版本 1 和版本 2 之间的 S3 客户端区别 适用于 Java 的 AWS SDK
<a name="migration-s3-client"></a>

在本主题中，适用于 Java 的 SDK 版本 1 和版本 2 中的 S3 客户端之间的差异按[迁移工具](migration-tool.md)的自动迁移方式进行组织。该工具支持将大多数方法从 V1 迁移到 V2，但有些方法需要手动迁移。除了 S3 客户端方法外，某些 S3 V1 类没有直接的 V2 等效项，需要您手动迁移这些方法。

**Contents**
+ [迁移工具支持的 V1 方法示例](#methods-tool-migration)
  + [`putObject`](#V1-V2-putobject)
  + [`getObject`](#V1-V2-getobject)
+ [需要手动迁移的 V1 方法](#s3-methods-manual-migration)
  + [使用 `S3ObjectId` 的 `getObject`](#V1s-getObject-using-V1s-S3ObjectId)
  + [使用 `ObjectMetadata` 的 `getETag`](#V1s-ObjectMetadata-using-V1s-getETag)
  + [`listNextBatchOfObjects`](#V1-listNextBatchOfObjects)
  + [`listNextBatchOfVersions`](#V1-listNextBatchOfVersions)
  + [`selectObjectContent`](#V1-selectObjectContent)
  + [`setBucketAcl`](#V1-setBucketAcl)
  + [`setObjectAcl`](#V1-setObjectAcl)
  + [`initiateMultipartUpload`](#V1-initiateMultipartUpload)
    + [示例迁移](#V1-initiateMultipartUpload-migration-ex)
    + [实施差异](#V1-initiateMultipartUpload-impl-diffs)
  + [`setRegion`](#V1-setRegion)
  + [`setS3ClientOptions(S3ClientOptions clientOptions)`](#V1-setS3ClientOptions)
  + [`setBucketLoggingConfiguration`](#V1-setBucketLoggingConfiguration)
  + [`setBucketLifecycleConfiguration`](#V1-setBucketLifecycleConfiguration)
  + [`setBucketTaggingConfiguration`](#V1-setBucketTaggingConfiguration)
+ [需要手动迁移的 V1 类](#s3-classes-manual-migration)
  + [`AccessControlList`](#V1-AccessControlList)
  + [`CannedAccessControlList`](#V1-CannedAccessControlList)
  + [`BucketNotificationConfiguration`](#V1-BucketNotificationConfiguration)
  + [`MultiFactorAuthentication`](#V1-MultifactorAuthentication)

## 迁移工具支持的 V1 方法示例
<a name="methods-tool-migration"></a>

迁移工具可自动将大多数方法从 V1 迁移到 V2。`putObject` 和 `getObject` 方法就是其中的两个示例。

### `putObject`
<a name="V1-V2-putobject"></a>

```
// SDK V1
s3Client.putObject("amzn-s3-demo-bucket", "my-key", "Hello World!");


// SDK V2
s3Client.putObject(req -> req 
    .bucket("amzn-s3-demo-bucket") 
    .key("my-key"), 
    RequestBody.fromString("Hello World!"));
```

### `getObject`
<a name="V1-V2-getobject"></a>

```
// SDK V1
S3Object object = s3Client.getObject("amzn-s3-demo-bucket", "my-key");
InputStream content = object.getObjectContent();


// SDK V2
ResponseInputStream<GetObjectResponse> response = s3Client.getObject(req -> req 
    .bucket("amzn-s3-demo-bucket") 
    .key("my-key"));
```

## 需要手动迁移的 V1 方法
<a name="s3-methods-manual-migration"></a>

您需要手动迁移以下 V1 S3 客户端方法。使用迁移工具时，您会在 V2 输出 Java 文件中看到一条注释，该注释会引导您进入此主题。

### V1 的 `getObject` 使用 V1 的 `S3ObjectId` 到 V2 的 `GetObjectRequest.builder()`
<a name="V1s-getObject-using-V1s-S3ObjectId"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
        .withRegion(Regions.US_WEST_2)
        .build();

S3ObjectId s3ObjectId = new S3ObjectId(
    "amzn-s3-demo-bucket",
    "object-key",
    "abc123version" 
);

GetObjectRequest getRequest= new GetObjectRequest(s3ObjectId);
S3Object s3ObjectVersioned = s3Client.getObject(getRequest);


// SDK V2
// V2 does not include a 'S3ObjectId' class. V2 uses the request builder pattern 
// to supply the bucket, key, and version parameters.
S3Client s3Client = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

GetObjectRequest getRequest = GetObjectRequest.builder()
    .bucket("amzn-s3-demo-bucket")
    .key("object-key")
    .versionId("abc123version")
    .build();

ResponseInputStream<GetObjectResponse> response = s3Client.getObject(getRequest);
```

### V1 的 `getETag()` 使用 V1 的 `ObjectMetadata` 到 V2 的 `GetObjectResponse.eTag()`
<a name="V1s-ObjectMetadata-using-V1s-getETag"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

S3Object object = s3ClientV1.getObject("amzn-s3-demo-bucket", "my-key");

// Double quotes are removed by the S3 client.
System.out.println(object.getObjectMetadata().getETag());

// SDK V2
S3Client s3ClientV2 = S3Client.builder()
        .region(Region.US_WEST_2)
        .build();

ResponseInputStream<GetObjectResponse> response = s3ClientV2.getObject(
        req -> req.bucket("amzn-s3-demo-bucket").key("my-key"));

// Double quotes are *NOT* removed. This is the unchanged ETag value as S3 sent it.
System.out.println(response.response().eTag());
```

### V1 的 `listNextBatchOfObjects` 到 V2 的 `listObjectsV2Paginator`
<a name="V1-listNextBatchOfObjects"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

ObjectListing objectListing = s3ClientV1.listObjects("bucket-name");
while (objectListing.isTruncated()) {
    objectListing = s3ClientV1.listNextBatchOfObjects(objectListing);
    for (S3ObjectSummary summary : objectListing.getObjectSummaries()) {
        System.out.println(summary.getKey());
    }
}


// SDK V2
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

ListObjectsV2Request request = ListObjectsV2Request.builder()
    .bucket("bucket-name")
    .build();

// V2 returns a paginator.
ListObjectsV2Iterable responses = s3Client.listObjectsV2Paginator(request);

for (ListObjectsV2Response page : responses) {
    page.contents().forEach(content -> {
        System.out.println(content.key());
    });
}
```

### V1 的 `listNextBatchOfVersions` 到 V2 的 `listObjectVersionsPaginator`
<a name="V1-listNextBatchOfVersions"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

VersionListing versionListing = s3ClientV1.listVersions("bucket-name", "prefix");
while (versionListing.isTruncated()) {
    versionListing = s3ClientV1.listNextBatchOfVersions(versionListing);
    for (S3VersionSummary version : versionListing.getVersionSummaries()) {
        System.out.println(version.getKey() + " " + version.getVersionId());
    }
}


// SDK V2
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

ListObjectVersionsRequest request = ListObjectVersionsRequest.builder()
    .bucket("bucket-name")
    .prefix("prefix")
    .build();

// V2 returns a paginator.
ListObjectVersionsIterable responses = s3ClientV2.listObjectVersionsPaginator(request);

for (ListObjectVersionsResponse page : responses) {
    page.versions().forEach(version -> {
        System.out.println(version.key() + " " + version.versionId());
    });
}
```

### `selectObjectContent`
<a name="V1-selectObjectContent"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

SelectObjectContentRequest request = new SelectObjectContentRequest()
    .withBucket("bucket-name")
    .withKey("object-key")
    .withExpression("select * from S3Object")
    .withExpressionType(ExpressionType.SQL)
 

SelectObjectContentResult result = s3ClientV1.selectObjectContent(request);
InputStream resultInputStream = result.getPayload().getRecordsInputStream();


// SDK V2
// In V2, 'selectObjectContent()' is available only on the S3AsyncClient. 
// V2 handles responses using an event-based 'SelectObjectContentEventStream'.
S3AsyncClient s3ClientV2 = S3AsyncClient.builder()
    .region(Region.US_WEST_2)
    .build();

SelectObjectContentRequest request = SelectObjectContentRequest.builder()
    .bucket("bucket-name")
    .key("object-key")
    .expression("select * from S3Object")
    .expressionType(ExpressionType.SQL)
    .build();
    
SelectObjectContentResponseHandler handler = new SelectObjectContentResponseHandler() {
    // Implement the required abstract methods such as 'onEventStream()'.
};

CompletableFuture<Void> future = s3ClientV2.selectObjectContent(request, handler);
// The 'SelectObjectContentResponseHandler' implementation processes the results.
```

### V1 的 `setBucketAcl` 到 V2 在 `PutBucketAclRequest.builder()` 上的 `acl` 方法
<a name="V1-setBucketAcl"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

AccessControlList acl = new AccessControlList();
acl.grantPermission(GroupGrantee.AllUsers, Permission.Read);
s3ClientV1.setBucketAcl("bucket-name", acl);


// SDK V2
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

PutBucketAclRequest request = PutBucketAclRequest.builder()
    .bucket("bucket-name")
    .acl(BucketCannedACL.PRIVATE)
    .build();

s3ClientV2.putBucketAcl(request);
```

### V1 的 `setObjectAcl` 到 V2 在 `PutObjectAclRequest.builder()` 上的 `acl` 方法
<a name="V1-setObjectAcl"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

AccessControlList acl = new AccessControlList();
acl.grantPermission(GroupGrantee.AllUsers, Permission.Read);
s3ClientV1.setObjectAcl("bucket-name", "object-key", acl);


// SDK V2
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

PutObjectAclRequest request = PutObjectAclRequest.builder()
    .bucket("bucket-name")
    .key("object-key")
    .acl(ObjectCannedACL.PRIVATE)
    .build();

s3ClientV2.putObjectAcl(request);
```

### V1 的 `initiateMultipartUpload` 到 V2 的 `createMultipartUpload`
<a name="V1-initiateMultipartUpload"></a>

#### 示例迁移
<a name="V1-initiateMultipartUpload-migration-ex"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();
    
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("application/zip");
metadata.addUserMetadata("mykey", "myvalue");

InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(
    "bucket-name", 
    "object-key",
    metadata
);

InitiateMultipartUploadResult initResponse = s3ClientV1.initiateMultipartUpload(initRequest);
String uploadId = initResponse.getUploadId();


// SDK V2
// V1 uses ObjectMetadata methods, whereas V2 uses a simple Map.
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

CreateMultipartUploadRequest createMultipartRequest = CreateMultipartUploadRequest.builder() 
    .bucket("amzn-s3-demo-bucket") 
    .key("object-key") 
    .contentType("application/zip") 
    .metadata(Collections.singletonMap("mykey", "myvalue"))
    .build();

CreateMultipartUploadResponse response = s3ClientV2.createMultipartUpload(createMultipartRequest);
String uploadId = response.uploadId();
```

#### 实施差异
<a name="V1-initiateMultipartUpload-impl-diffs"></a>

以下方法的默认 `Content-Type` 标头值有所不同，如下表所示。


****  

| SDK 版本 | 方法 | 默认 `Content-Type` 值 | 
| --- | --- | --- | 
| 版本 1 | [initiateMultipartUpload](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3Client.html#initiateMultipartUpload-com.amazonaws.services.s3.model.InitiateMultipartUploadRequest-) | application/octet-stream | 
| 版本 2 | [createMultipartUpload](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3AsyncClient.html#createMultipartUpload(software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest)) | binary/octet-stream | 

### V1 的 `setRegion` 到 V2 在客户端生成器上的 `region` 方法
<a name="V1-setRegion"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard().build();
s3ClientV1.setRegion(Region.getRegion(Regions.US_WEST_2));


// SDK V2
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();
```

### V1 的 `setS3ClientOptions(S3ClientOptions clientOptions)`
<a name="V1-setS3ClientOptions"></a>

V2 没有在 `setS3ClientOptions` 方法中使用单个 `S3ClientOptions` 对象，而是在客户端生成器上提供方法来设置选项。

### V1 的 `setBucketLoggingConfiguration` 到 V2 的 `putBucketLogging`
<a name="V1-setBucketLoggingConfiguration"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

BucketLoggingConfiguration loggingConfig = new BucketLoggingConfiguration();
loggingConfig.setDestinationBucketName("log-bucket");

SetBucketLoggingConfigurationRequest request = new SetBucketLoggingConfigurationRequest(
    "amzn-s3-demo-source-bucket",
    loggingConfig
);

s3ClientV1.setBucketLoggingConfiguration(request);


// SDK V2
// In V2, V1's 'BucketLoggingConfiguration' is replaced by 'BucketLoggingStatus' 
// and 'LoggingEnabled'.
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

LoggingEnabled loggingEnabled = LoggingEnabled.builder()
    .targetBucket("log-bucket")
    .build();

BucketLoggingStatus loggingStatus = BucketLoggingStatus.builder()
    .loggingEnabled(loggingEnabled)
    .build();

PutBucketLoggingRequest request = PutBucketLoggingRequest.builder()
    .bucket("amzn-s3-demo-source-bucket")
    .bucketLoggingStatus(loggingStatus)
    .build();

s3ClientV2.putBucketLogging(request);
```

### V1 的 `setBucketLifecycleConfiguration` 到 V2 的 `putBucketLifecycleConfiguration`
<a name="V1-setBucketLifecycleConfiguration"></a>

```
// SDK V1
BucketLifecycleConfiguration.Rule rule = new BucketLifecycleConfiguration.Rule()
    .withId("Archive and Delete Rule")
    .withPrefix("documents/")
    .withStatus(BucketLifecycleConfiguration.ENABLED)
    .withTransitions(Arrays.asList(
        new Transition()
            .withDays(30)
            .withStorageClass(StorageClass.StandardInfrequentAccess.toString()),
        new Transition()
            .withDays(90)
            .withStorageClass(StorageClass.Glacier.toString())
    ))
    .withExpirationInDays(365);

BucketLifecycleConfiguration configuration = new BucketLifecycleConfiguration()
    .withRules(Arrays.asList(rule));

s3ClientV1.setBucketLifecycleConfiguration("amzn-s3-demo-bucket", configuration);


// SDK V2
LifecycleRule rule = LifecycleRule.builder()
    .id("Archive and Delete Rule")
    .filter(LifecycleRuleFilter.builder()
        .prefix("documents/")
        .build())
    .status(ExpirationStatus.ENABLED)
    .transitions(Arrays.asList(
        Transition.builder()
            .days(30)
            .storageClass(TransitionStorageClass.STANDARD_IA)
            .build(),
        Transition.builder()
            .days(90)
            .storageClass(TransitionStorageClass.GLACIER)
            .build()
    ))
    .expiration(LifecycleExpiration.builder()
        .days(365)
        .build())
    .build();

PutBucketLifecycleConfigurationRequest request = PutBucketLifecycleConfigurationRequest.builder()
    .bucket("amzn-s3-demo-bucket")
    .lifecycleConfiguration(BucketLifecycleConfiguration.builder()
        .rules(rule)
        .build())
    .build();

s3ClientV2.putBucketLifecycleConfiguration(request);
```

### V1 的 `setBucketTaggingConfiguration` 到 V2 的 `putBucketTagging`
<a name="V1-setBucketTaggingConfiguration"></a>

```
// SDK V1
List<TagSet> tagsets = new ArrayList<>();
TagSet tagSet = new TagSet();
tagSet.setTag("key1", "value1");
tagSet.setTag("key2", "value2");
tagsets.add(tagSet);

BucketTaggingConfiguration bucketTaggingConfiguration = new BucketTaggingConfiguration();
bucketTaggingConfiguration.setTagSets(tagsets);

SetBucketTaggingConfigurationRequest request = new SetBucketTaggingConfigurationRequest(
    "amzn-s3-demo-bucket",
    bucketTaggingConfiguration
);

s3ClientV1.setBucketTaggingConfiguration(request);


// SDK V2
Tagging tagging = Tagging.builder()
    .tagSet(Arrays.asList(
        Tag.builder()
            .key("key1")
            .value("value1")
            .build(),
        Tag.builder()
            .key("key2")
            .value("value2")
            .build()
    ))
    .build();

PutBucketTaggingRequest request = PutBucketTaggingRequest.builder()
    .bucket("amzn-s3-demo-bucket")
    .tagging(tagging)
    .build();

s3ClientV2.putBucketTagging(request);
```

## 需要手动迁移的 V1 类
<a name="s3-classes-manual-migration"></a>

### V1 的 `AccessControlList` 到 V2 的 `AccessControlPolicy`
<a name="V1-AccessControlList"></a>

```
// SDK V1
AccessControlList aclV1 = new AccessControlList();
aclV1.setOwner(new Owner("owner-id", "owner-name"));
aclV1.grantPermission(GroupGrantee.AllUsers, Permission.Read);

// SDK V2
// To migrate from V1 to V2, replace direct 'AccessControlList' modifications with an
// 'AccessControlPolicy.builder()' that contains both owner information and grants. 
// Note that V2's approach requires building the complete permission set upfront rather than modifying permissions incrementally.
AccessControlPolicy acpV2 = AccessControlPolicy.builder()
    .owner(Owner.builder()
        .id("owner-id")
        .displayName("owner-name")
        .build())
    .grants(Arrays.asList(
         Grant.builder()
            .grantee(Grantee.builder()
                 .type(Type.GROUP)
                 .uri("http://acs.amazonaws.com/groups/global/AllUsers") 
                 .build())
             .permission(Permission.READ)
             .build()
     ))
     .build();
```

### V1 的 `CannedAccessControlList` 枚举到 V2 的 `BucketCannedACL` 和 `ObjectCannedACL` 枚举
<a name="V1-CannedAccessControlList"></a>

```
// SDK V1
// In V1, 'CannedAccessControlList' is an enumeration of predefined ACLs.
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard().build();

// Creating a bucket.
s3ClientV1.setBucketAcl("bucket-name", CannedAccessControlList.PublicRead);

// Creating an object.
PutObjectRequest putObjectRequest = new PutObjectRequest("bucket-name", "object-key", file)
    .withCannedAcl(CannedAccessControlList.PublicRead);
s3ClientV1.putObject(putObjectRequest);


// SDK V2
// V2 replaces V1's 'CannedAccessControlList' with 'BucketCannedACL' for buckets and 'ObjectCannedACL' for objects.
S3Client s3ClientV2 = S3Client.builder().build();

// Creating a bucket.
PutBucketAclRequest bucketRequest = PutBucketAclRequest.builder()
    .bucket("bucket-name")
    .acl(BucketCannedACL.PRIVATE)
    .build();
s3ClientV2.putBucketAcl(bucketRequest);

// Creating an object.
PutObjectRequest objectRequest = PutObjectRequest.builder()
    .bucket("bucket-name")
    .key("object-key")
    .acl(ObjectCannedACL.PUBLIC_READ)
    .build();
s3ClientV2.putObject(objectRequest, RequestBody.fromFile(file));
```

### V1 的 `BucketNotificationConfiguration` 到 V2 的 `NotificationConfiguration`
<a name="V1-BucketNotificationConfiguration"></a>

```
//SDK V1
BucketNotificationConfiguration notificationConfig = new BucketNotificationConfiguration();

// Adding configurations by name
notificationConfig.addConfiguration("lambdaConfig", 
    new LambdaConfiguration("arn:aws:lambda:function", "s3:ObjectCreated:"));

notificationConfig.addConfiguration("topicConfig",
    new TopicConfiguration("arn:aws:sns:topic", "s3:ObjectRemoved:"));

notificationConfig.addConfiguration("queueConfig",
    new QueueConfiguration("arn:aws:sqs:queue", "s3:ObjectRestore:*"));

s3Client.setBucketNotificationConfiguration("bucket", notificationConfig);


// SDK V2
// In V2, V1's BucketNotificationConfiguration is renamed to NotificationConfiguration. 
// V2 contains no common abstract class for LambdaFunction/Topic/Queue configurations.
NotificationConfiguration notificationConfig = NotificationConfiguration.builder()
    .lambdaFunctionConfigurations(
        LambdaFunctionConfiguration.builder()
            .lambdaFunctionArn("arn:aws:lambda:function")
            .events(Event.valueOf("s3:ObjectCreated:"))
            .build())
    .topicConfigurations(
        TopicConfiguration.builder()
            .topicArn("arn:aws:sns:topic")
            .events(Event.valueOf("s3:ObjectRemoved:"))
            .build())
    .queueConfigurations(
        QueueConfiguration.builder()
            .queueArn("arn:aws:sqs:queue")
            .events(Event.valueOf("s3:ObjectRestore:*"))
            .build())
    .build();

s3Client.putBucketNotificationConfiguration(req -> req
    .bucket("bucket")
    .notificationConfiguration(notificationConfig));
```

### V1 的 `MultiFactorAuthentication` 到 V2 在请求生成器上的 `mfa` 方法
<a name="V1-MultifactorAuthentication"></a>

```
// SDK V1
AmazonS3 s3ClientV1 = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_WEST_2)
    .build();

BucketVersioningConfiguration versioningConfig = new BucketVersioningConfiguration()
    .withStatus(BucketVersioningConfiguration.ENABLED);

// Create an MFA configuration object.
MultiFactorAuthentication mfa = new MultiFactorAuthentication(
    "arn:aws:iam::1234567890:mfa/user",
    "123456"
);

// Create the request object.
SetBucketVersioningConfigurationRequest request = new SetBucketVersioningConfigurationRequest(
    "bucket-name",
    versioningConfig,
    mfa
);

// Send the request.
s3ClientV1.setBucketVersioningConfiguration(request);


// SDK V2
// V2 replaces V1's MultiFactorAuthentication POJO with parameters you set on the request builder.
S3Client s3ClientV2 = S3Client.builder()
    .region(Region.US_WEST_2)
    .build();

PutBucketVersioningRequest request = PutBucketVersioningRequest.builder()
    .bucket("bucket-name")
    .versioningConfiguration(VersioningConfiguration.builder()
        .status(BucketVersioningStatus.ENABLED)
        .build())
    .mfa("arn:aws:iam::1234567890:mfa/user 123456")  // Single method takes both MFA erial number and token.
    .build();

s3ClientV2.putBucketVersioning(request);
```

# 将传输管理器从版本 1 迁移到版本 2 适用于 Java 的 AWS SDK
<a name="migration-s3-transfer-manager"></a>

本迁移指南介绍了 Transfer Manager v1 和 S3 Transfer Manager v2 之间的主要差异，包括构造函数更改、方法映射和常见操作的代码示例。在了解这些差异之后，您可以成功迁移现有的 Transfer Manager 代码，以便充分利用 v2 中改进的性能和异步操作。

**关于 AWS SDK 迁移工具**  
 适用于 Java 的 AWS SDK 提供了一种自动[迁移工具](migration-tool.md)，可以将 v1 传输管理器 API 的大部分迁移到 v2。但是，该迁移工具不支持几项 v1 Transfer Manager 功能。对于这些情况，您需要按照本主题中的指导手动迁移 Transfer Manager 代码。  
在本指南中，**迁移状态**显示了迁移工具是否可以自动迁移构造函数、方法或功能：  
**支持**：迁移工具可以自动转换此代码
**不支持**：您需要手动迁移代码
即使对于标记为“支持”的项目，也要检查迁移结果并进行彻底测试。Transfer Manager 迁移涉及从同步操作到异步操作的重大架构更改。

## 概述
<a name="s3-tm-migration-overview"></a>

S3 Transfer Manager v2 对 Transfer Manager API 进行了重大更改。S3 Transfer Manager v2 AWS 基于异步操作构建，可提供更好的性能，尤其是在您使用基于 CRT 的 Amazon S3 客户端时。

### 主要区别
<a name="s3-tm-migration-key-differences"></a>
+ **软件包**：`com.amazonaws.services.s3.transfer` → `software.amazon.awssdk.transfer.s3`
+ **类名**：`TransferManager` → `S3TransferManager`
+ **客户端依赖项**：同步 Amazon S3 客户端 → 异步 Amazon S3 客户端（`S3AsyncClient`）
+ **架构**：同步操作 → 使用 `CompletableFuture` 的异步操作
+ **性能**：通过 AWS 基于 CRT 的客户端支持得到增强

## 高级别更改
<a name="s3-tm-migration-high-level-changes"></a>


| 方面 | V1 | V2 | 
| --- | --- | --- | 
| Maven 依赖关系 | aws-java-sdk-s3 | s3-transfer-manager | 
| 软件包 | com.amazonaws.services.s3.transfer | software.amazon.awssdk.transfer.s3 | 
| 主要的类 | TransferManager | S3TransferManager | 
| Amazon S3 客户端 | AmazonS3（同步） | S3AsyncClient（异步） | 
| 返回类型 | 阻塞操作 | CompletableFuture<T> | 

## Maven 依赖项
<a name="s3-tm-migration-dependencies"></a>


| V1 | V2 | 
| --- | --- | 
|  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>>1.12.7871</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-java-sdk-s3</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.31.682</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>s3-transfer-manager</artifactId><br />    </dependency><br />    <!-- Optional: For enhanced performance with AWS CRT --><br />    <dependency><br />        <groupId>software.amazon.awssdk.crt</groupId><br />        <artifactId>aws-crt</artifactId><br />        <version>0.38.53</version><br />    </dependency><br /></dependencies></pre>  | 

1 [最新版本](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom)。 2 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。 3 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk.crt/aws-crt)。

## 客户端构造函数迁移
<a name="s3-tm-migration-client-constructor"></a>

### 支持的构造函数（自动迁移）
<a name="s3-tm-migration-supported-constructors"></a>


| V1 构造函数 | V2 等效项 | 迁移状态 | 
| --- | --- | --- | 
| new TransferManager() | S3TransferManager.create() | 支持 | 
| TransferManagerBuilder. defaultTransferManager() | S3TransferManager.create() | 支持 | 
| TransferManagerBuilder. standard().build() | S3TransferManager.builder().build() | 支持 | 
| new TransferManager(AWSCredentials) | S3TransferManager.builder() .s3Client(S3AsyncClient.builder() .credentialsProvider(...).build()) .build() | 支持 | 
| new TransferManager( AWSCredentialsProvider) | S3TransferManager.builder() .s3Client(S3AsyncClient.builder() .credentialsProvider(...).build()) .build() | 支持 | 

### 不支持的构造函数（需要手动迁移）
<a name="s3-tm-migration-unsupported-constructors"></a>


| V1 构造函数 | V2 等效项 | 迁移说明 | 
| --- | --- | --- | 
| new TransferManager(AmazonS3) | 需要手动迁移 | 单独创建 S3AsyncClient | 
| new TransferManager(AmazonS3, ExecutorService) | 需要手动迁移 | 创建 S3AsyncClient 并配置执行器 | 
| new TransferManager(AmazonS3, ExecutorService, boolean) | 需要手动迁移 | 不支持 shutDownThreadPools 参数 | 

### 手动迁移示例
<a name="s3-tm-migration-manual-examples"></a>

**V1 代码：**

```
AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();
TransferManager transferManager = new TransferManager(s3Client);
```

**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();
```

## 客户端方法迁移
<a name="s3-tm-migration-client-methods"></a>

目前，迁移工具支持基本 `copy`、`download`、`upload`、`uploadDirectory`、`downloadDirectory`、`resumeDownload` 和 `resumeUpload` 方法。

### 核心传输方法
<a name="s3-tm-migration-core-transfer-methods"></a>


| V1 方法 | V2 方法 | 返回类型更改 | 迁移状态 | 
| --- | --- | --- | --- | 
| upload(String, String, File) | uploadFile(UploadFileRequest) | Upload → FileUpload | 支持 | 
| upload(PutObjectRequest) | upload(UploadRequest) | Upload → Upload | 支持 | 
| download(String, String, File) | downloadFile(DownloadFileRequest) | Download → FileDownload | 支持 | 
| download(GetObjectRequest, File) | downloadFile(DownloadFileRequest) | Download → FileDownload | 支持 | 
| copy(String, String, String, String) | copy(CopyRequest) | Copy → Copy | 支持 | 
| copy(CopyObjectRequest) | copy(CopyRequest) | Copy → Copy | 支持 | 
| uploadDirectory(String, String, File, boolean) | uploadDirectory( UploadDirectoryRequest) | MultipleFileUpload → DirectoryUpload | 支持 | 
| downloadDirectory(String, String, File) | downloadDirectory( DownloadDirectoryRequest) | MultipleFileDownload → DirectoryDownload | 支持 | 

### 可恢复的传输方法
<a name="s3-tm-migration-resumable-methods"></a>


| V1 方法 | V2 方法 | 迁移状态 | 
| --- | --- | --- | 
| resumeUpload(PersistableUpload) | resumeUploadFile(ResumableFileUpload) | 支持 | 
| resumeDownload(PersistableDownload) | resumeDownloadFile(ResumableFileDownload) | 支持 | 

### 生命周期方法
<a name="s3-tm-migration-lifecycle-methods"></a>


| V1 方法 | V2 方法 | 迁移状态 | 
| --- | --- | --- | 
| shutdownNow() | close() | 支持 | 
| shutdownNow(boolean) | 使用 close() 方法手动调整代码 | 不支持 | 

### 不支持的 V1 客户端方法
<a name="s3-tm-migration-unsupported-methods"></a>


| V1 方法 | V2 替代方案 | 注意 | 
| --- | --- | --- | 
| abortMultipartUploads(String, Date) | 使用低级别 Amazon S3 客户端 | 不支持 | 
| getAmazonS3Client() | 单独保存引用 | 不支持；v2 中没有 getter | 
| getConfiguration() | 单独保存引用 | 不支持；v2 中没有 getter | 
| uploadFileList(...) | 多次调用 uploadFile() | 不支持 | 
| 使用 TransferStateChangeListener 参数的 copy 方法 | 使用 TransferListener | [参见手动迁移示例](#tm-unsupported-client-methods-copy) | 
| 使用 S3ProgressListener 参数的 download 方法 | 使用 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/progress/TransferListener.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/transfer/s3/progress/TransferListener.html) | [参见手动迁移示例](#tm-unsupported-client-methods-download) | 
|  使用 4 个或更多参数的 `downloadDirectory` 方法  |  | [参见手动迁移示例](#tm-unsupported-client-methods-download-dir) | 
| 使用 ObjectMetadataProvider 参数的 upload 方法 | 在请求中设置元数据 | [参见手动迁移示例](#tm-unsupported-client-methods-upload) | 
| 使用 \$1Provider 参数的 uploadDirectory 方法 | 在请求中设置标签 | [参见手动迁移示例](#tm-unsupported-client-methods-uploadDirectory) | 

#### 使用 `TransferStateChangeListener` 参数的 `copy` 方法
<a name="tm-unsupported-client-methods-copy"></a>
+ `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);
```

#### 使用 `S3ProgressListener` 参数的 `download` 方法
<a name="tm-unsupported-client-methods-download"></a>
+ `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.
```

#### 使用 4 个或更多参数的 `downloadDirectory` 方法
<a name="tm-unsupported-client-methods-download-dir"></a>
+ `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);
```

#### 使用 `ObjectMetadata` 参数的 `upload` 方法
<a name="tm-unsupported-client-methods-upload"></a>
+ `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();
```

#### 使用 `ObjectMetadataProvider` 参数的 `uploadDirectory`
<a name="tm-unsupported-client-methods-uploadDirectory"></a>
+ `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);
```

## 模型对象迁移
<a name="s3-tm-migration-model-objects"></a>

在中 AWS SDK for Java 2.x，许多`TransferManager`模型对象已经过重新设计，不再支持 v1 模型对象中可用的几个 getter 和 setter 方法。

在 v2 中，您可以使用 `CompletableFuture<T>` 类在传输完成时执行操作，无论传输是成功还是出现异常。如果需要，您可以使用 `join()` 方法来等待完成。

### 核心传输对象
<a name="s3-tm-migration-core-transfer-objects"></a>


| V1 类 | V2 类 | 迁移状态 | 
| --- | --- | --- | 
| TransferManager | S3TransferManager | 支持 | 
| TransferManagerBuilder | S3TransferManager.Builder | 支持 | 
| Transfer | Transfer | 支持 | 
| AbortableTransfer | Transfer | 支持（没有单独的类） | 
| Copy | Copy | 支持 | 
| Download | FileDownload | 支持 | 
| Upload | Upload / FileUpload | 支持 | 
| MultipleFileDownload | DirectoryDownload | 支持 | 
| MultipleFileUpload | DirectoryUpload | 支持 | 

### 持久化对象
<a name="s3-tm-migration-persistence-objects"></a>


| V1 类 | V2 类 | 迁移状态 | 
| --- | --- | --- | 
| PersistableDownload | ResumableFileDownload | 支持 | 
| PersistableUpload | ResumableFileUpload | 支持 | 
| PersistableTransfer | ResumableTransfer | 支持 | 
| PauseResult<T> | 直接可恢复对象 | 不支持 | 

### 结果对象
<a name="s3-tm-migration-result-objects"></a>


| V1 类 | V2 类 | 迁移状态 | 
| --- | --- | --- | 
| CopyResult | CompletedCopy | 支持 | 
| UploadResult | CompletedUpload | 支持 | 

### 配置对象
<a name="s3-tm-migration-configuration-objects"></a>


| V1 类 | V2 类 | 迁移状态 | 
| --- | --- | --- | 
| TransferManagerConfiguration | MultipartConfiguration（在 Amazon S3 客户端上） | 支持 | 
| TransferProgress | TransferProgress \$1 TransferProgressSnapshot | 支持 | 
| KeyFilter | DownloadFilter | 支持 | 

### 不支持的对象
<a name="s3-tm-migration-unsupported-objects"></a>


| V1 类 | V2 替代方案 | 迁移状态 | 
| --- | --- | --- | 
| PauseStatus | 不支持 | 不支持 | 
| UploadContext | 不支持 | 不支持 | 
| ObjectCannedAclProvider | PutObjectRequest.builder().acl() | 不支持 | 
| ObjectMetadataProvider | PutObjectRequest.builder().metadata() | 不支持 | 
| ObjectTaggingProvider | PutObjectRequest.builder().tagging() | 不支持 | 
| PresignedUrlDownload | 不支持 | 不支持 | 

## TransferManagerBuilder 配置迁移
<a name="s3-tm-migration-builder-configuration"></a>

### 配置更改
<a name="migration-transfer-manager-config-changes"></a>

您需要为 v2 传输管理器设置的配置更改取决于您使用的 S3 客户端。您可以选择 AWS 基于 CRT 的 S3 客户端或基于 Java 的标准的 S3 异步客户端。有关差异的信息，请参阅 [中的 S3 客户端 AWS SDK for Java 2.x](examples-s3.md#s3-clients) 主题。

------
#### [ Use the AWS CRT-based S3 client ]


****  

| 设置 | v1 | v2-使用 AWS 基于 CRT 的 S3 客户端的传输管理器 | 
| --- | --- | --- | 
|    （获取生成器）  |  <pre>TransferManagerBuilder tmBuilder = <br />   TransferManagerBuilder.standard();</pre>  |  <pre>S3TransferManager.Builder tmBuilder  = <br />  S3TransferManager.builder();</pre>  | 
|    S3 客户端  |  <pre>tmBuilder.withS3Client(...);<br />tmBuilder.setS3Client(...);</pre>  |  <pre>tmBuilder.s3Client(...);</pre>  | 
|    执行程序  |  <pre>tmBuilder.withExecutorFactory(...);<br />tmBuilder.setExecutorFactory(...);</pre>  |  <pre>tmBuilder.executor(...);</pre>  | 
|    关闭线程池  |  <pre>tmBuilder.withShutDownThreadPools(...);<br />tmBuilder.setShutdownThreadPools(...);</pre>  | 不支持。关闭 S3TransferManager 时，不会关闭提供的执行程序 | 
|    最小上传段大小  |  <pre>tmBuilder.withMinimumUploadPartSize(...);<br />tmBuilder.setMinimumUploadPartSize(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.crtBuilder().<br />      minimumPartSizeInBytes(...).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    分段上传阈值  |  <pre>tmBuilder.withMultipartUploadThreshold(...);<br />tmBuilder.setMultipartUploadThreshold(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.crtBuilder().<br />      thresholdInBytes(...).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    最小复制段大小  |  <pre>tmBuilder.withMultipartCopyPartSize(...);<br />tmBuilder.setMultipartCopyPartSize(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.crtBuilder().<br />      minimumPartSizeInBytes(...).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    分段复制阈值  |  <pre>tmBuilder.withMultipartCopyThreshold(...);<br />tmBuilder.setMultipartCopyThreshold(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.crtBuilder().<br />      thresholdInBytes(...).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    禁用并行下载  |  <pre>tmBuilder.withDisableParallelDownloads(...);<br />tmBuilder.setDisableParallelDownloads(...);</pre>  | 通过将默认禁用分段的基于 Java 的标准 S3 客户端传递给 Transfer Manager 来禁用并行下载。<pre>S3AsyncClient s3 =<br />   S3AsyncClient.builder().build();<br /><br />tmBuilder.s3Client(s3);</pre> | 
|    始终计算分段 md5  |  <pre>tmBuilder.withAlwaysCalculateMultipartMd5(...);<br />tmBuilder.setAlwaysCalculateMultipartMd5(...);</pre>  | 不支持。 | 

------
#### [ Use Java-based S3 async client ]


****  

| 设置 | v1 | v2 - 使用基于 Java 的 S3 异步客户端的 Transfer Manager | 
| --- | --- | --- | 
|    （获取生成器）  |  <pre>TransferManagerBuilder tmBuilder = <br />   TransferManagerBuilder.standard();</pre>  |  <pre>S3TransferManager.Builder tmBuilder  = <br />  S3TransferManager.builder();</pre>  | 
|    S3 客户端  |  <pre>tmBuilder.withS3Client(...);<br />tmBuilder.setS3Client(...);</pre>  |  <pre>tmBuilder.s3Client(...);</pre>  | 
|    执行程序  |  <pre>tmBuilder.withExecutorFactory(...);<br />tmBuilder.setExecutorFactory(...);</pre>  |  <pre>tmBuilder.executor(...);</pre>  | 
|    关闭线程池  |  <pre>tmBuilder.withShutDownThreadPools(...);<br />tmBuilder.setShutdownThreadPools(...);</pre>  | 不支持。关闭 S3TransferManager 时，不会关闭提供的执行程序 | 
|    最小上传段大小  |  <pre>tmBuilder.withMinimumUploadPartSize(...);<br />tmBuilder.setMinimumUploadPartSize(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.builder()<br />    .multipartConfiguration(cfg -><br />        cfg.minimumPartSizeInBytes(...)).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    分段上传阈值  |  <pre>tmBuilder.withMultipartUploadThreshold(...);<br />tmBuilder.setMultipartUploadThreshold(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.builder()<br />    .multipartConfiguration(cfg -><br />        cfg.thresholdInBytes(...)).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    最小复制段大小  |  <pre>tmBuilder.withMultipartCopyPartSize(...);<br />tmBuilder.setMultipartCopyPartSize(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.builder()<br />    .multipartConfiguration(cfg -><br />        cfg.minimumPartSizeInBytes(...)).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    分段复制阈值  |  <pre>tmBuilder.withMultipartCopyThreshold(...);<br />tmBuilder.setMultipartCopyThreshold(...);</pre>  |  <pre>S3AsyncClient s3 = S3AsyncClient.builder()<br />    .multipartConfiguration(cfg -><br />        cfg.thresholdInBytes(...)).build();<br /><br />tmBuilder.s3Client(s3);</pre>  | 
|    禁用并行下载  |  <pre>tmBuilder.withDisableParallelDownloads(...);<br />tmBuilder.setDisableParallelDownloads(...);</pre>  | 通过将默认禁用分段的基于 Java 的标准 S3 客户端传递给 Transfer Manager 来禁用并行下载。<pre>S3AsyncClient s3 =<br />   S3AsyncClient.builder().build();<br /><br />tmBuilder.s3Client(s3);</pre> | 
|    始终计算分段 md5  |  <pre>tmBuilder.withAlwaysCalculateMultipartMd5(...);<br />tmBuilder.setAlwaysCalculateMultipartMd5(...);</pre>  | 不支持。 | 

------

## 行为更改
<a name="s3-tm-migration-behavior-changes"></a>

### 异步操作
<a name="s3-tm-migration-async-operations"></a>

**V1（阻塞）：**

```
Upload upload = transferManager.upload("amzn-s3-demo-bucket", "key", file);
upload.waitForCompletion(); // Blocks until complete
```

**V2（异步）：**

```
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());
});
```

### 错误处理
<a name="s3-tm-migration-error-handling"></a>

**V1：**如果任何子请求失败，则目录传输将完全失败。

**V2：**即使某些子请求失败，目录传输也会成功完成。明确检查错误：

```
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()));
}
```

### 通过字节范围提取进行并行下载
<a name="migration-transfer-manager-behavior-fetches"></a>

在 v2 SDK 中启用自动并行传输功能后，S3 Transfer Manager 使用[字节范围提取](https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance-guidelines.html#optimizing-performance-guidelines-get-range)来并行检索对象的特定部分（分段下载）。使用 v2 下载对象的方式不取决于对象最初的上传方式。所有下载都可以从高吞吐量和并发性中受益。

相比之下，使用 v1 Transfer Manager 时，对象最初的上传方式确实很重要。v1 Transfer Manager 检索对象各个分段的方式与上传分段的方式相同。如果对象最初是作为单个对象上传的，则 v1 Transfer Manager 无法通过使用子请求来加速下载过程。

# 在解析 Amazon S3 时 URIs 从版本 1 到版本 2 的变化
<a name="migration-s3-uri-parser"></a>

本主题详细介绍了解析 Amazon S3 URIs 从版本 1 (v1) 到版本 2 (v2.) 时所做的更改。

## 高级别更改
<a name="migration-3-uri-parser-api-changes"></a>

在 v1 中，要开始解析 S3 URI，可使用构造函数对 `AmazonS3URI` 进行实例化。在 v2 中，在 `S3Utilities` 的实例上调用 `parseUri()`，以便返回 `S3URI`。


****  

| 更改 | v1 |  v2 | 
| --- | --- | --- | 
|    Maven 依赖项  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.5871</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency>  <br />        <groupId>com.amazonaws</groupId><br />        <artifactId>s3</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.27.212</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>s3</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| 软件包名称 | com.amazonaws.services.s3 | software.amazon.awssdk.services.s3 | 
| 类名 | [AmazonS3URI](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3URI.html) | [S3URI](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Uri.html) | 

1 [最新版本](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom)。2 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

## API 更改
<a name="migration-3-uri-parser-api-changes"></a>


| 行为 | v1 |  v2 | 
| --- | --- | --- | 
| 解析 S3 URI。 |  <pre>URI uri = URI.create( "https://s3.amazonaws.com");<br /><br />AmazonS3Uri s3Uri = <br />    new AmazonS3URI(uri, false);</pre>  |  <pre>S3Client s3Client = S3Client.create();<br />S3Utilities s3Utilities =<br />    s3Client.utilities();<br /><br />S3Uri s3Uri =<br />    s3Utilities.parseUri(uri);</pre>  | 
| 从 S3 URI 检索存储桶名称。 |  <pre>String bucket = s3Uri.getBucket();</pre>  |  <pre>Optional<String> bucket = s3Uri.bucket();</pre>  | 
| 检索密钥。 |  <pre>String key = s3Uri.getKey();</pre>  |  <pre>Optional<String> key = s3Uri.key();</pre>  | 
| 检索区域。 |  <pre>String region = s3Uri.getRegion();</pre>  |  <pre>Optional<Region> region = s3Uri.region();<br /><br />String region;<br />if (s3Uri.region().isPresent()) {<br />    region = s3Uri.region().get().id();<br />}</pre>  | 
|  检索 S3 URI 是否为路径风格。  |  <pre>boolean isPathStyle = s3Uri.isPathStyle();</pre>  |  <pre>boolean isPathStyle = s3Uri.isPathStyle();</pre>  | 
| 检索版本 ID。 |  <pre>String versionId = s3Uri.getVersionId();</pre>  |  <pre>Optional<String> versionId = <br />    s3Uri.firstMatchingRawQueryParameter("versionId");</pre>  | 
| 检索查询参数。 | 不适用 |  <pre>Map<String, List<String>> queryParams =<br />    s3Uri.rawQueryParameters();</pre>  | 

### 行为更改
<a name="migration-s3-uri-parser-behavior-changes"></a>

#### URL 编码
<a name="migration-s3-uri-parser-behavior-changes-URLencoding"></a>

v1 提供了传入标志的选项，用于指定 URI 是否应进行 URL 编码。默认值为 `true`。

在 v2 中，不支持 URL 编码。如果您使用包含保留字符或不安全字符的对象键或查询参数，则必须对其进行 URL 编码。例如，您需要将空格 `" "` 替换为 `%20`。

# S3 事件通知 API 从版本 1 到版本 2 的更改
<a name="migration-s3-event-notification"></a>

本主题详细说明了 S3 事件通知 API 从 适用于 Java 的 AWS SDK版本 1.x（v1）到版本 2（v2）的更改。

## 高级别更改
<a name="migration-s3-event-notification-hl"></a>

### 结构变化
<a name="migration-s3-event-notification-hl-struct"></a>

V1 对 `EventNotificationRecord` 类型及其属性使用静态内部类，而 v2 对 `EventNotificationRecord` 类型使用单独的公共类。

### 命名约定更改
<a name="migration-s3-event-notification-hl-naming"></a>

*在 v1 中，属性类名称包含后缀 Ent *it* y，而 v2 为了更简单的命名省略了这个后缀：例如，用 eventData 代替。*eventDataEntity**

## 依赖项、软件包和类名的更改
<a name="migration-s3-event-notification-deps"></a>

在 v1 中，S3 事件通知 API 类会随着 S3 模块（artifactId `aws-java-sdk-s3`）一起以传递依赖方式导入。但在 v2 中，您需要在 `s3-event-notifications` 构件上添加依赖项。


****  

| 更改 | v1 |  v2 | 
| --- | --- | --- | 
|    Maven 依赖项  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.X.X</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-java-sdk-s3</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.X.X1</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>s3-event-notifications</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| 软件包名称 | com.amazonaws.services.s3.event | software.amazon.awssdk.eventnotifications.s3.model | 
| 类名 |  [S3EventNotification](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.html) [S3 EventNotification .S3 EventNotificationRecord](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.S3EventNotificationRecord.html) [S3 EventNotification。 GlacierEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.GlacierEventDataEntity.html) [S3 EventNotification。 IntelligentTieringEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.IntelligentTieringEventDataEntity.html) [S3 EventNotification。 LifecycleEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.LifecycleEventDataEntity.html) [S3 EventNotification。 ReplicationEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.ReplicationEventDataEntity.html) [S3 EventNotification。 RequestParametersEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.RequestParametersEntity.html) [S3 EventNotification。 ResponseElementsEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.ResponseElementsEntity.html) [S3 EventNotification。 RestoreEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.RestoreEventDataEntity.html) [S3 EventNotification .S3 BucketEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.S3BucketEntity.html) [S3 EventNotification .S3Entity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.S3Entity.html) [S3 EventNotification .S3 ObjectEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.S3ObjectEntity.html) [S3 EventNotification。 TransitionEventDataEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.TransitionEventDataEntity.html) [S3 EventNotification。 UserIdentityEntity](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/event/S3EventNotification.UserIdentityEntity.html)  |   [S3EventNotification](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotification.html) [S3EventNotificationRecord](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3EventNotificationRecord.html) [GlacierEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/GlacierEventData.html) [IntelligentTieringEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/IntelligentTieringEventData.html) [LifecycleEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/LifecycleEventData.html) [ReplicationEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/ReplicationEventData.html) [RequestParameters](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/RequestParameters.html) [ResponseElements](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/ResponseElements.html) [RestoreEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/RestoreEventData.html) [S3Bucket](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3Bucket.html) [S3](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3.html) [S3OBJECT](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/S3Object.html) [TransitionEventData](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/TransitionEventData.html) [UserIdentity](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/eventnotifications/s3/model/UserIdentity.html)  | 

1 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

## API 更改
<a name="migration-s3-event-notification-API-changes"></a>

### JSON 和 `S3EventNotification` 的相互转换
<a name="migration-s3-event-notification-API-changes-conv"></a>


| 使用案例 | v1 |  v2 | 
| --- | --- | --- | 
| 从 JSON 字符串创建 S3EventNotification |  <pre>S3EventNotification notification = <br />        S3EventNotification.parseJson(message.body());</pre>  |  <pre>S3EventNotification notification = <br />        S3EventNotification.fromJson(message.body());</pre>  | 
| 将 S3EventNotification 转换为 JSON 字符串 |  <pre>String json = notification.toJson();</pre>  |  <pre>String json = notification.toJson();</pre>  | 

### `S3EventNotification` 的访问属性
<a name="migration-s3-event-notification-API-changes-attr"></a>


| 使用案例 | v1 |  v2 | 
| --- | --- | --- | 
| 从通知中检索记录 |  <pre>List<S3EventNotification.S3EventNotificationRecord> records = <br />        notifcation.getRecords();</pre>  |  <pre>List<S3EventNotificationRecord> records = <br />        notification.getRecords();</pre>  | 
| 从记录列表中检索记录 |  <pre>S3EventNotification.S3EventNotificationRecord record = <br />        records.stream().findAny().get();</pre>  |  <pre>S3EventNotificationRecord record = <br />        records.stream().findAny().get();</pre>  | 
| 检索 Glacier 事件数据 |  <pre>S3EventNotification.GlacierEventDataEntity glacierEventData =<br />        record.getGlacierEventData();</pre>  |  <pre>GlacierEventData glacierEventData = <br />        record.getGlacierEventData();</pre>  | 
| 从 Glacier 事件中检索还原事件数据 |  <pre>S3EventNotification.RestoreEventDataEntity restoreEventData = <br />        glacierEventData.getRestoreEventDataEntity();</pre>  |  <pre>RestoreEventData restoreEventData = <br />        glacierEventData.getRestoreEventData();</pre>  | 
| 检索请求参数 |  <pre>S3EventNotification.RequestParametersEntity requestParameters = <br />        record.getRequestParameters();</pre>  |  <pre>RequestParameters requestParameters = <br />        record.getRequestParameters();</pre>  | 
| 检索智能分层事件数据 |  <pre>S3EventNotification.IntelligentTieringEventDataEntity tieringEventData = <br />        record.getIntelligentTieringEventData();</pre>  |  <pre>IntelligentTieringEventData intelligentTieringEventData = <br />        record.getIntelligentTieringEventData();</pre>  | 
| 检索生命周期事件数据 |  <pre>S3EventNotification.LifecycleEventDataEntity lifecycleEventData = <br />        record.getLifecycleEventData();</pre>  |  <pre>LifecycleEventData lifecycleEventData = <br />        record.getLifecycleEventData();</pre>  | 
| 以枚举形式检索事件名称 |  <pre>S3Event eventNameAsEnum = record.getEventNameAsEnum();</pre>  |  <pre>//getEventNameAsEnum does not exist; use 'getEventName()'<br />String eventName = record.getEventName();</pre>  | 
| 检索复制事件数据 |  <pre>S3EventNotification.ReplicationEventDataEntity replicationEntity = <br />        record.getReplicationEventDataEntity();</pre>  |  <pre>ReplicationEventData replicationEventData = <br />        record.getReplicationEventData();</pre>  | 
| 检索 S3 存储桶和对象信息 |  <pre>S3EventNotification.S3Entity s3 = record.getS3();</pre>  |  <pre>S3 s3 = record.getS3();</pre>  | 
| 检索用户身份信息 |  <pre>S3EventNotification.UserIdentityEntity userIdentity = <br />        record.getUserIdentity();</pre>  |  <pre>UserIdentity userIdentity = <br />        record.getUserIdentity();</pre>  | 
| 检索响应元素 |  <pre>S3EventNotification.ResponseElementsEntity responseElements = <br />        record.getResponseElements();</pre>  |  <pre>ResponseElements responseElements = <br />        record.getResponseElements();</pre>  | 

## 迁移 `aws-lambda-java-events` 库版本
<a name="migration-s3-events-notification-lambda-lib"></a>

如果您习惯在 Lambda 函数中处理 S3 通知事件，我们建议您升级到最新的 3.x.x 版本。[aws-lambda-java-events](https://github.com/aws/aws-lambda-java-libs/tree/main/aws-lambda-java-events)最新版本消除了 S3 事件通知 API 中对 适用于 Java 的 AWS SDK 1.x 的所有依赖。

若要详细了解 `aws-lambda-java-events` 库和适用于 Java 的 SDK 2.x 在处理 S3 事件通知方面的差异，请参阅[使用 Java 库在 Lambda 中处理 S3 事件：以及 AWS SDK for Java 2.x `aws-lambda-java-events`](examples-s3-event-notifications.md#s3-event-notif-processing-options)。

# 配置文件更改
<a name="migration-profile-file"></a>

AWS SDK for Java 2.x 解析 `~/.aws/config` 和 `~/.aws/credentials` 中的配置文件定义，以便更贴近地模拟 AWS CLI 解析文件的方式。

适用于 Java 的 SDK 2.x：
+ 通过按顺序检查 `$HOME`、`$USERPROFILE`（仅 Windows）、`$HOMEDRIVE`、`$HOMEPATH`（仅 Windows），然后检查 `user.home` 系统属性，来解析路径开头处的 `~/` 或 `~`（后跟文件系统的默认路径分隔符）。
+ 查找 `AWS_SHARED_CREDENTIALS_FILE` 环境变量，而不是查找 `AWS_CREDENTIAL_PROFILES_FILE`。
+ 在配置文件中，如果配置项名称开头未包含单词 `profile`，则静默忽略该配置项定义。
+ 静默忽略不包含字母数字、下划线或连接号字符的配置项定义（为配置文件移除了开头的 `profile` 单词之后）。
+ 合并同一文件中重复的配置项定义的设置。
+ 合并配置文件和凭证文件中重复的配置项定义的设置。
+ 如果在同一个文件中找到 `[profile foo]` 和 `[foo]`，则不合并设置。
+ 如果在配置文件中找到 `[profile foo]` 和 `[foo]`，则使用 `[profile foo]` 中的设置。
+ 使用同一个文件和配置文件中最后一个重复设置的值。
+ 认识用于定义注释的 `;` 和 `#`。
+ 认识配置项定义中用于定义注释的 `;` 和 `#`，即使这些字符与右括号相邻也要认出来。
+ 只有当 `;` 和 `#` 前面有空格时，才在设置值中将其视为注释。
+ 只有当 `;` 和 `#` 前面没有空格时，才在设置值中将这些符号及后面的所有内容视为注释。
+ 将基于角色的凭证视为优先级最高的凭证。如果用户指定了 `role_arn` 属性，2.x SDK 将始终使用基于角色的凭证。
+ 将基于会话的凭证视为优先级第二高的凭证。如果未使用基于角色的凭证且用户指定了 `aws_access_key_id` 和 `aws_session_token` 属性，则 2.x SDK 将始终使用基于会话的凭证。
+ 如果未使用基于角色的凭证和基于会话的凭证且用户指定了 `aws_access_key_id` 属性，则使用基本凭证。

# 环境变量和系统属性更改
<a name="migration-env-and-system-props"></a>


| 1.x 环境变量 | 1.x 系统属性 | 2.x 环境变量 | 2.x 系统属性 | 
| --- | --- | --- | --- | 
| AWS\$1ACCESS\$1KEY\$1IDAWS\$1ACCESS\$1KEY | aws.accessKeyId | AWS\$1ACCESS\$1KEY\$1ID | aws.accessKeyId | 
| AWS\$1SECRET\$1KEYAWS\$1SECRET\$1ACCESS\$1KEY | aws.secretKey | AWS\$1SECRET\$1ACCESS\$1KEY | aws.secretAccessKey | 
| AWS\$1SESSION\$1TOKEN | aws.sessionToken | AWS\$1SESSION\$1TOKEN | aws.sessionToken | 
| AWS\$1REGION | aws.region | AWS\$1REGION | aws.region | 
| AWS\$1CONFIG\$1FILE |   | AWS\$1CONFIG\$1FILE | aws.configFile | 
| AWS\$1CREDENTIAL\$1PROFILES\$1FILE |   | AWS\$1SHARED\$1CREDENTIALS\$1FILE | aws.sharedCredentialsFile | 
| AWS\$1PROFILE | aws.profile | AWS\$1PROFILE | aws.profile | 
| AWS\$1EC2\$1METADATA\$1DISABLED | com.amazonaws.sdk.disableEc2Metadata | AWS\$1EC2\$1METADATA\$1DISABLED | aws.disableEc2Metadata | 
|   | com.amazonaws.sdk.ec2MetadataServiceEndpointOverride | AWS\$1EC2\$1METADATA\$1SERVICE\$1ENDPOINT | aws.ec2MetadataServiceEndpoint | 
| AWS\$1CONTAINER\$1CREDENTIALS\$1RELATIVE\$1URI |   | AWS\$1CONTAINER\$1CREDENTIALS\$1RELATIVE\$1URI | aws.containerCredentialsPath | 
| AWS\$1CONTAINER\$1CREDENTIALS\$1FULL\$1URI |   | AWS\$1CONTAINER\$1CREDENTIALS\$1FULL\$1URI | aws.containerCredentialsFullUri | 
| AWS\$1CONTAINER\$1AUTHORIZATION\$1TOKEN |   | AWS\$1CONTAINER\$1AUTHORIZATION\$1TOKEN | aws.containerAuthorizationToken | 
| AWS\$1CBOR\$1DISABLED | com.amazonaws.sdk.disableCbor | CBOR\$1ENABLED | aws.cborEnabled | 
| AWS\$1ION\$1BINARY\$1DISABLE | com.amazonaws.sdk.disableIonBinary | BINARY\$1ION\$1ENABLED | aws.binaryIonEnabled | 
| AWS\$1EXECUTION\$1ENV |   | AWS\$1EXECUTION\$1ENV | aws.executionEnvironment | 
|   | com.amazonaws.sdk.disableCertChecking | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
|   | com.amazonaws.sdk.enableDefaultMetrics | [不支持](https://github.com/aws/aws-sdk-java-v2/issues/23) | [不支持](https://github.com/aws/aws-sdk-java-v2/issues/23) | 
|   | com.amazonaws.sdk.enableThrottledRetry | [不支持](https://github.com/aws/aws-sdk-java-v2/issues/645) | [不支持](https://github.com/aws/aws-sdk-java-v2/issues/645) | 
|   | com.amazonaws.regions.RegionUtils.fileOverride | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
|   | com.amazonaws.regions.RegionUtils.disableRemote | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
|   | com.amazonaws.services.s3.disableImplicitGlobalClients | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 
|   | com.amazonaws.sdk.enableInRegionOptimizedMode | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 不支持（[请求功能](https://github.com/aws/aws-sdk-java-v2/issues/new)） | 

# Waiter 从版本 1 到版本 2 的变化
<a name="migration-waiters"></a>

本主题详细介绍了 Waiter 的功能从版本 1（v1）到版本 2（v2）的变化。

下表展示了 DynamoDB Waiter 的具体差异。其他服务的 Waiter 也遵循同样的模式。

## 高级别更改
<a name="migration-waiters-api-changes"></a>

Waiter 类与服务位于相同的 Maven 构件中。


| 更改 | v1 | v2 | 
| --- | --- | --- | 
|    Maven 依赖项  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.6801</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>dynamodb</artifactId><br />    </dependency><br /></dependencies><br /></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.27.102</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>dynamodb</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| 软件包名称 | com.amazonaws.services.dynamodbv2.waiters | software.amazon.awssdk.services.dynamodb.waiters | 
| 类名 |  `[AmazonDynamoDBWaiters](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/waiters/AmazonDynamoDBWaiters.html)`  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/migration-waiters.html)  | 

1 [最新版本](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom)。2 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

## API 更改
<a name="migration-cf-presign-behavior-changes"></a>


| 更改 | v1 | v2 | 
| --- | --- | --- | 
| 创建 Waiter |  <pre>AmazonDynamoDB client = AmazonDynamoDBClientBuilder <br />                            .standard().build();<br />AmazonDynamoDBWaiters waiter = client.waiters();</pre>  | 同步：<pre>DynamoDbClient client = DynamoDbClient.create();<br />DynamoDbWaiter waiter = client.waiter();</pre>异步：<pre>DynamoDbAsyncClient asyncClient = <br />        DynamoDbAsyncClient.create();<br />DynamoDbAsyncWaiter waiter = asyncClient.waiter();</pre> | 
| 等待表完成创建 | 同步：<pre>waiter.tableExists()<br />    .run(new WaiterParameters<>(<br />        new DescribeTableRequest(tableName)));</pre>异步：<pre>waiter.tableExists()<br />    .runAsync(new WaiterParameters()<br />      .withRequest(new DescribeTableRequest(tableName)),<br />          new WaiterHandler() {<br />              @Override<br />              public void onWaitSuccess(<br />                  AmazonWebServiceRequest amazonWebServiceRequest) {<br />                    System.out.println("Table creation succeeded");<br />              }<br /><br />              @Override<br />              public void onWaitFailure(Exception e) {<br />                  e.printStackTrace();<br />              }<br />          }).get();</pre> |  同步： <pre>WaiterResponse<DescribeTableResponse> waiterResponse =<br />    waiter.waitUntilTableExists(<br />        r -> r.tableName("myTable"));<br />waiterResponse.matched().response()<br />       .ifPresent(System.out::println);</pre> 异步： <pre>waiter.waitUntilTableExists(r -> r.tableName(tableName))<br />           .whenComplete((r, t) -> {<br />               if (t != null) {<br />                   t.printStackTrace();<br />               } else {<br />                   System.out.println(<br />                        "Table creation succeeded");<br />               }<br />           }).join();</pre>  | 

## 配置更改
<a name="migration-waiters-config"></a>


| 更改 | v1 | v2 | 
| --- | --- | --- | 
| 轮询策略（最大尝试次数和固定延迟） |  <pre>MaxAttemptsRetryStrategy maxAttemptsRetryStrategy = <br />        new MaxAttemptsRetryStrategy(10);<br /><br />FixedDelayStrategy fixedDelayStrategy = <br />        new FixedDelayStrategy(3);<br /><br />PollingStrategy pollingStrategy = <br />        new PollingStrategy(maxAttemptsRetryStrategy, <br />                fixedDelayStrategy);<br /><br />waiter.tableExists().run(<br />        new WaiterParameters<>(<br />            new DescribeTableRequest(tableName)), <br />                pollingStrategy);</pre>  |  <pre><br />FixedDelayBackoffStrategy fixedDelayBackoffStrategy = <br />        FixedDelayBackoffStrategy<br />            .create(Duration.ofSeconds(3));<br /><br />waiter.waitUntilTableExists(r -> r.tableName(tableName),<br />        c -> c.maxAttempts(10)<br />                .backoffStrategy(fixedDelayBackoffStrategy));</pre>  | 

# EC2 元数据实用程序从版本 1 到版本 2 的变化
<a name="migration-imds"></a>

本主题详细介绍了 SDK for Java Amazon Elastic Compute Cloud（EC2）元数据实用程序从版本 1（v1）到版本 2（v2）的变化。

## 高级别更改
<a name="migration-imds-high-level-changes"></a>


****  

| 更改 | v1 |  v2 | 
| --- | --- | --- | 
|    Maven 依赖项  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.5871</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-java-sdk-core</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.27.212</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>imds</artifactId><br />    </dependency><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>apache-client3</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| 软件包名称 |  com.amazonaws.util  |  software.amazon.awssdk.imds  | 
| 实例化方法 |  使用静态实用程序方法；不进行实例化： <pre>String localHostName = <br />           EC2MetadataUtils.getLocalHostName();</pre>  |  使用静态工厂方法： <pre>Ec2MetadataClient client = Ec2MetadataClient.create();</pre> 或者使用生成器方法： <pre>Ec2MetadataClient client = Ec2MetadataClient.builder()<br />    .endpointMode(EndpointMode.IPV6)<br />    .build();</pre>  | 
| 客户端类型 | 仅同步实用程序方法：EC2MetadataUtils |  同步：`Ec2MetadataClient` 异步：`Ec2MetadataAsyncClient`  | 

1 [最新版本](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom)。2 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

3 注意 v2 的 `apache-client` 模块声明。EC2 元数据实用程序的 V2 需要为同步元数据客户端实现 `SdkHttpClient` 接口，或为异步元数据客户端实现 `SdkAsyncHttpClient` 接口。[在中配置 HTTP 客户端 AWS SDK for Java 2.x](http-configuration.md)部分显示了您可以使用的 HTTP 客户端列表。

### 请求元数据
<a name="migration-imds-fetching-changes"></a>

在 v1 中，您可以使用不接受任何参数的静态方法来请求 EC2 资源的元数据。相比之下，在 v2 中，您需要将 EC2 资源的路径指定为参数。下表显示了不同的方法。


****  

| v1 |  v2 | 
| --- | --- | 
|  <pre>String userMetaData = EC2MetadataUtils.getUserData();</pre>  |  <pre>Ec2MetadataClient client = Ec2MetadataClient.create();<br />Ec2MetadataResponse response = <br />                client.get("/latest/user-data");<br />String userMetaData = <br />                response.asString();</pre>  | 

请参阅[实例元数据类别](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/instancedata-data-categories.html)，查找请求元数据时需要提供的路径。

**注意**  
在 v2 中使用实例元数据客户端时，您应该针对检索元数据的所有请求使用同一客户端。

 

## 行为更改
<a name="migration-imds-behavior-changes"></a>

### JSON 数据
<a name="migration-imds-behavior-json"></a>

在 EC2 上，本地运行的实例元数据服务（IMDS）以 JSON 格式的字符串形式返回一些元数据。[实例身份文档](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/instance-identity-documents.html)的动态元数据就是一个例子。

v1 API 针对每种实例身份元数据包含不同的方法，而 v2 API 会直接返回 JSON 字符串。要处理 JSON 字符串，您可以使用[文档 API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/document/package-summary.html) 解析响应并浏览 JSON 结构。

下表比较了在 v1 和 v2 中检索实例身份文档元数据的方式。


****  

| 使用案例 | v1 |  v2 | 
| --- | --- | --- | 
| 检索区域 |  <pre>InstanceInfo instanceInfo = <br />        EC2MetadataUtils.getInstanceInfo();<br />String region = instanceInfo.getRegion();</pre>  |  <pre>Ec2MetadataResponse response = <br />    client.get("/latest/dynamic/instance-identity/document");<br />Document instanceInfo = response.asDocument();<br />String region = instanceInfo.asMap().get("region").asString();</pre>  | 
| 检索实例 ID |  <pre>InstanceInfo instanceInfo = <br />        EC2MetadataUtils.getInstanceInfo();<br />String instanceId = instanceInfo.instanceId;</pre>  |  <pre>Ec2MetadataResponse response = <br />    client.get("/latest/dynamic/instance-identity/document");<br />Document instanceInfo = response.asDocument();<br />String instanceId = instanceInfo.asMap().get("instanceId").asString();</pre>  | 
| 检索实例类型 |  <pre>InstanceInfo instanceInfo = <br />        EC2MetadataUtils.getInstanceInfo();<br />String instanceType = instanceInfo.instanceType();</pre>  |  <pre>Ec2MetadataResponse response = <br />    client.get("/latest/dynamic/instance-identity/document");<br />Document instanceInfo = response.asDocument();<br />String instanceType = instanceInfo.asMap().get("instanceType").asString();</pre>  | 

### 端点解析差异
<a name="migration-imds-behavior-endpoint-res"></a>

下表显示了 SDK 为将端点解析到 IMDS 而检查的位置。这些位置按优先级降序列出。


****  

| v1 |  v2 | 
| --- | --- | 
| 系统属性：com.amazonaws.sdk.ec2MetadataServiceEndpointOverride | 客户端生成器配置方法：endpoint(...) | 
| 环境变量：AWS\$1EC2\$1METADATA\$1SERVICE\$1ENDPOINT | 系统属性：aws.ec2MetadataServiceEndpoint | 
| 默认值：http://169.254.169.254 | Config 文件：\$1.aws/config，及 ec2\$1metadata\$1service\$1endpoint 设置 | 
|  | 与已解析的 endpoint-mode 相关联的值  | 
|  | 默认值：http://169.254.169.254 | 

### v2 中的端点解析
<a name="migration-imds-behavior-endpoint-res2"></a>

如果您使用生成器显式设置端点，该端点值的优先级高于所有其他设置。当以下代码执行时，`aws.ec2MetadataServiceEndpoint` 系统属性和 config 文件 `ec2_metadata_service_endpoint` 设置如果存在，将被忽略。

```
Ec2MetadataClient client = Ec2MetadataClient
  .builder()
  .endpoint(URI.create("endpoint.to.use"))
  .build();
```

#### 端点模式
<a name="migration-imds-behavior-endpoint-mode"></a>

在 v2 中，您可以指定端点模式，将元数据客户端配置为使用或的默认端点值。 IPv4 IPv6端点模式不适用于 v1。使用的默认值为`http://169.254.169.254`和 IPv4 fo `http://[fd00:ec2::254]` r IPv6。

下表按优先级降序显示了设置端点模式时可以采用的不同方法。


****  

|  |  | 可能的值 | 
| --- | --- | --- | 
| 客户端生成器配置方法：endpointMode(...) |  <pre>Ec2MetadataClient client = Ec2MetadataClient<br />  .builder()<br />  .endpointMode(EndpointMode.IPV4)<br />  .build();</pre>  | EndpointMode.IPV4, EndpointMode.IPV6 | 
| 系统属性 | aws.ec2MetadataServiceEndpointMode | IPv4、IPv6（大小写没有影响） | 
| Config 文件：\$1.aws/config | ec2\$1metadata\$1service\$1endpoint 设置 | IPv4、IPv6（大小写没有影响） | 
| 未在前面的方法中指定 | IPv4 被使用了 |  | 

#### 在 v2 中，SDK 如何解析`endpoint`或`endpoint-mode`
<a name="migration-imds-behavior-endpoint-res2-which"></a>

1. SDK 使用您通过客户端生成器在代码中设置的值，并忽略任何外部设置。由于在客户端生成器上同时调用 `endpoint` 和 `endpointMode` 时，SDK 会抛出异常，因此 SDK 将使用您所用的任一方法中的端点值。

1. 如果您没有在代码中设置值，SDK 会查看外部配置；首先查找系统属性，然后是 config 文件中的设置。

   1. SDK 会先检查端点值。如果找到值，则使用该值。

   1. 如果 SDK 仍未找到值，则会查找端点模式设置。

1. 最后，如果 SDK 未找到任何外部设置，并且您尚未在代码中配置元数据客户端，则 SDK 将使用 IPv4 值`http://169.254.169.254`。

### IMDSv2
<a name="migration-imds-behavior-imdsv2"></a>

Amazon EC2 定义了两种访问实例元数据的方法：
+ 实例元数据服务版本 1 (IMDSv1)-请求/响应方法
+ 实例元数据服务版本 2 (IMDSv2)-面向会话的方法

下表比较了 Java SDKs 如何与 IMDS 配合使用。


****  

| v1 |  v2 | 
| --- | --- | 
| IMDSv2 默认情况下使用 | 始终使用 IMDSv2 | 
| 尝试为每个请求获取会话令牌， IMDSv1 如果无法获取会话令牌，则回退到会话令牌 | 将会话令牌保存在内部缓存中，该令牌可重复用于多个请求 | 

适用于 Java 的 SDK 2.x 仅支持 IMDSv2 ，不能回退到。 IMDSv1

## 配置差异
<a name="migration-imds-config-diffs"></a>

下表列出了不同的配置选项。


****  

| 配置 | v1 |  v2 | 
| --- | --- | --- | 
|  重试 | 配置不可用 | 可通过生成器方法 retryPolicy(...) 配置 | 
| HTTP | 连接超时可通过 AWS\$1METADATA\$1SERVICE\$1TIMEOUT 环境变量配置。默认值为 1 秒。 | 通过将 HTTP 客户端传递给生成器方法 httpClient(...) 即可进行配置。HTTP 客户端的默认连接超时为 2 秒。 | 

### v2 HTTP 配置示例
<a name="migration-imds-http-conf-v2-ex"></a>

以下示例演示了如何配置元数据客户端。此示例配置连接超时并使用 Apache HTTP 客户端。

```
SdkHttpClient httpClient = ApacheHttpClient.builder()
    .connectionTimeout(Duration.ofSeconds(1))
    .build();

Ec2MetadataClient imdsClient = Ec2MetadataClient.builder()
    .httpClient(httpClient)
    .build();
```

# Amazon CloudFront 预签名从版本 1 更改为版本 2
<a name="migration-cloudfront-presigning"></a>

本主题详细介绍了 Amazon CloudFront 从版本 1 (v1) 到版本 2 (v2) 的变化。

## 高级别更改
<a name="migration-cloudfront-presigning-api-changes"></a>


****  

| 更改 | v1 |  v2 | 
| --- | --- | --- | 
|    Maven 依赖项  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.5871</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency>  <br />        <groupId>com.amazonaws</groupId><br />        <artifactId>cloudfront</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.27.212</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>cloudfront</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| 软件包名称 | com.amazonaws.services.cloudfront | software.amazon.awssdk.services.cloudfront | 
| 类名 |  [CloudFrontUrlSigner](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/cloudfront/CloudFrontUrlSigner.html) [CloudFrontCookieSigner](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/cloudfront/CloudFrontCookieSigner.html)  |  [CloudFrontUtilities](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.html) [SignedUrl](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudfront/url/SignedUrl.html) [CannedSignerRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudfront/model/CannedSignerRequest.html) [CustomSignerRequest](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/cloudfront/model/CustomSignerRequest.html)  | 

1 [最新版本](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom)。2 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

## API 更改
<a name="migration-cf-presign-behavior-changes"></a>


| 行为 | v1 |  v2 | 
| --- | --- | --- | 
| 构建标准请求 | 参数直接传递给 API。 |  <pre>CannedSignerRequest cannedRequest =<br />      CannedSignerRequest.builder()<br />                         .resourceUrl(resourceUrl)<br />                         .privateKey(privateKey)<br />                         .keyPairId(keyPairId)<br />                         .expirationDate(expirationDate)<br />                         .build();</pre>  | 
| 构建自定义请求 | 参数直接传递给 API。 |  <pre>CustomSignerRequest customRequest =<br />      CustomSignerRequest.builder()<br />                         .resourceUrl(resourceUrl)<br />                         .resourceUrlPattern(resourceUrlPattern)<br />                         .privateKey(keyFile)<br />                         .keyPairId(keyPairId)<br />                         .expirationDate(expirationDate)<br />                         .activeDate(activeDate)<br />                         .ipRange(ipRange)<br />                         .build();</pre>  | 
| 生成签名 URL（标准） |  <pre>String signedUrl =<br />  CloudFrontUrlSigner.getSignedURLWithCannedPolicy(<br />    resourceUrl, keyPairId, privateKey, expirationDate);</pre>  |  <pre>CloudFrontUtilities cloudFrontUtilities =<br />    CloudFrontUtilities.create();<br /><br />SignedUrl signedUrl =        <br />    cloudFrontUtilities.getSignedUrlWithCannedPolicy(cannedRequest);<br /><br />String url = signedUrl.url();<br /></pre>  | 
| 生成签名 Cookie（自定义） |  <pre>CookiesForCustomPolicy cookies =<br />    CloudFrontCookieSigner.getCookiesForCustomPolicy(<br />        resourceUrl, privateKey, keyPairId, expirationDate, <br />        activeDate, ipRange);<br /></pre>  |  <pre>CloudFrontUtilities cloudFrontUtilities =<br />    CloudFrontUtilities.create();<br /><br />CookiesForCustomPolicy cookies =<br />     cloudFrontUtilities.getCookiesForCustomPolicy(customRequest);<br /></pre>  | 

### v2 中重构的 Cookie 标头
<a name="migration-cf-presign-behavior-headers"></a>

在 Java v1 中，Java SDK 以 `Map.Entry<String, String>` 形式提供 Cookie 标头。

```
Map.Entry<String, String> signatureMap = cookies.getSignature();
String signatureKey = signatureMap.getKey(); // "CloudFront-Signature"
String signatureValue = signatureMap.getValue(); // "[SIGNATURE_VALUE]"
```

Java v2 SDK 以单个 `String` 形式提供整个标头。

```
String signatureHeaderValue = cookies.signatureHeaderValue(); // "CloudFront-Signature=[SIGNATURE_VALUE]"
```

# IAM 策略生成器 API 从版本 1 到版本 2 的变化
<a name="migration-iam-policy-builder"></a>

本主题详细说明了 IAM 策略生成器 API 从版本 1（v1）到版本 2（v2）发生的变化。

## 高级别更改
<a name="migration-iam-policy-builder-high-level"></a>


****  

| 更改 | v1 |  v2 | 
| --- | --- | --- | 
|    Maven 依赖项  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.5871</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-java-sdk-core</artifactId><br />    </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.27.212</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>iam-policy-builder</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| 软件包名称 | com.amazonaws.auth.policy | software.amazon.awssdk.policybuilder.iam | 
| 类名 |  [Policy](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Policy.html) [Statement](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Statement.html) [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/migration-iam-policy-builder.html)  |  [IamPolicy](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamPolicy.html) [IamStatement](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamStatement.html) [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/migration-iam-policy-builder.html)  | 

1 [最新版本](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom)。2 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

## API 更改
<a name="migration-iam-policy-builder-api"></a>


****  

| 设置 | v1 |  v2 | 
| --- | --- | --- | 
|  实例化策略 |  <pre>Policy policy = new Policy();</pre>  |  <pre>IamPolicy.Builder policyBuilder = IamPolicy.builder();<br />...<br />IamPolicy policy = policyBuilder.build();</pre>  | 
|    设置 ID  |  <pre>policy.withtId(...);<br />policy.setId(...);</pre>  |  <pre>policyBuilder.id(...);</pre>  | 
|    设置版本  | 不适用 - 使用默认版本 2012-10-17 |  <pre>policyBuilder.version(...);</pre>  | 
|    创建语句  |  <pre>Statement statement = <br />    new Statement(Effect.Allow)<br />            .withActions(...)<br />            .withConditions(...)<br />            .withId(...)<br />            .withPrincipals(...)<br />            .withResources(...);</pre>  |  <pre>IamStatement statement = <br />    IamStatement.builder()<br />            .effect(IamEffect.ALLOW)<br />            .actions(...)<br />            .notActions(...)<br />            .conditions(...)<br />            .sid(...)<br />            .principals(...)<br />            .notPrincipals(...)<br />            .resources(...)<br />            .notResources(...)<br />            .build()</pre>  | 
|    设置语句  |  <pre>policy.withStatements(statement);<br />policy.setStatements(statement);</pre>  |  <pre>policyBuilder.addStatement(statement);</pre>  | 

## 构建语句时的差异
<a name="migration-iam-policy-builder-statement"></a>

### 操作
<a name="migration-iam-policy-builder-statement-actions"></a>

#### v1
<a name="migration-iam-policy-builder-statement-actions.v1"></a>

v1 SDK 为服务操作使用 [`enum` 类型](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Action.html)，表示策略语句中的 `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_action.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_action.html)` 元素。以下 `enum` 类型是一些示例。
+ `[IdentityManagementActions](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/actions/IdentityManagementActions.html)`
+ `[DynamoDBv2Actions](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/actions/DynamoDBv2Actions.html)`
+ `[SQSActions](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/actions/SQSActions.html)`

以下示例显示 `SQSActions` 的 `SendMessage` 常量。

```
Action action = SQSActions.SendMessage;
```

在 v1 中，您无法为语句指定 `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notaction.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notaction.html)` 元素。

#### v2
<a name="migration-iam-policy-builder-statement-actions.v2"></a>

在 v2 中，[IamAction](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamAction.html)接口代表所有操作。要指定[特定于服务的操作](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_action.html)元素，请向 `create` 方法传递一个字符串，如以下代码所示。

```
IamAction action = IamAction.create("sqs:SendMessage");
```

如以下代码所示，使用 v2 时，您可为语句指定 `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notaction.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notaction.html)`。

```
IamAction action = IamAction.create("sqs:SendMessage");
IamStatement.builder().addNotAction(action);
```

### Conditions
<a name="migration-iam-policy-builder-statement-conditions"></a>

#### v1
<a name="migration-iam-policy-builder-statement-conditions-v1"></a>

为了表示语句条件，v1 SDK 使用 [https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Condition.html](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Condition.html) 的子类。
+  [ArnCondition](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/ArnCondition.html) 
+  [BooleanCondition](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/BooleanCondition.html)
+  [DateCondition](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/DateCondition.html)
+ [IpAddressCondition](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/IpAddressCondition.html)
+ [NumericCondition](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/NumericCondition.html)
+ [ StringCondition ](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/conditions/StringCondition.html)

每个 `Condition` 子类都定义一个比较 `enum` 类型来帮助定义条件。例如，下面显示了条件的*不相似*[字符串比较](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_String)。

```
Condition condition = new StringCondition(StringComparisonType.StringNotLike, "key", "value");
```

#### v2
<a name="migration-iam-policy-builder-statement-conditions-v2"></a>

在 v2 中，您可以使用 `[IamCondition](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamCondition.html)` 并提供 `[IamConditionOperator](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamConditionOperator.html)`（包含所有类型的 `enums` 条件）来为策略语句构建条件。

```
IamCondition condition = IamCondition.create(IamConditionOperator.STRING_NOT_LIKE, "key", "value");
```

### 资源
<a name="migration-iam-policy-builder-statement-resources"></a>

#### v1
<a name="migration-iam-policy-builder-statement-resources-v1"></a>

策略语句的 `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html)` 元素用 SDK 的 `[Resource](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Resource.html)` 类表示。在构造函数中以字符串形式提供 ARN。以下子类提供了便捷的构造函数。
+ [S3BucketResource](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/resources/S3BucketResource.html)
+ [S3ObjectResource](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/resources/S3ObjectResource.html)
+ [SQSQueue资源](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/resources/SQSQueueResource.html)

在 v1 中，您可以通过调用 `withIsNotType` 方法为 `[Resource](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Resource.html)` 指定 `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html)` 元素，如以下语句所示。

```
Resource resource = new Resource("arn:aws:s3:::amzn-s3-demo-bucket").withIsNotType(true);
```

#### v2
<a name="migration-iam-policy-builder-statement-resources-v2"></a>

在 v2 中，您可以通过将 ARN 传递给 `IamResource.create` 方法来创建 `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html)` 元素。

```
IamResource resource = IamResource.create("arn:aws:s3:::amzn-s3-demo-bucket");
```

`[IamResource](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamResource.html)` 可以设置为 *[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html)* 元素，如以下代码段所示。

```
IamResource resource = IamResource.create("arn:aws:s3:::amzn-s3-demo-bucket");
IamStatement.builder().addNotResource(resource);
```

`IamResource.ALL` 表示所有资源。

### 主体
<a name="migration-iam-policy-builder-statement-principal"></a>

#### v1
<a name="migration-iam-policy-builder-statement-principal-v1"></a>

v1 SDK 提供以下 `[Principal](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/policy/Principal.html)` 类来表示包括所有成员的主体的类型：
+ `AllUsers`
+ `AllServices`
+ `AllWebProviders`
+ `All`

您无法向语句添加 `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html)` 元素。

#### v2
<a name="migration-iam-policy-builder-statement-principal-v2"></a>

在 v2 中，`IamPrincipal.ALL` 表示所有主体：

要表示其他类型主体中的所有成员，请在创建 `IamPrincipal` 时使用 `[IamPrincipalType](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/policybuilder/iam/IamPrincipalType.html)` 类。
+ `IamPrincipal.create(IamPrincipalType.AWS,"*")` 适用于所有用户。
+ `IamPrincipal.create(IamPrincipalType.SERVICE,"*")` 适用于所有服务。
+ `IamPrincipal.create(IamPrincipalType.FEDERATED,"*")` 适用于所有 Web 提供程序。
+ `IamPrincipal.create(IamPrincipalType.CANONICAL_USER,"*")` 适用于所有规范用户。

在创建策略语句时，您可以使用 `addNotPrincipal` 方法来表示 `[https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html)` 元素，如以下语句所示。

```
IamPrincipal principal = IamPrincipal.create(IamPrincipalType.AWS, "arn:aws:iam::444455556666:root");
IamStatement.builder().addNotPrincipal(principal);
```

# 在使用 DynamoDB 时发生了变化，从版本 1 变为版本 2 适用于 Java 的 AWS SDK
<a name="migration-ddb-mapper"></a>



**Topics**
+ [DynamoDB 映射 API 的版本 1 和版本 2 之间的区别 适用于 Java 的 AWS SDK](ddb-mapping.md)
+ [文档 API 的版本 1 和版本 2 之间的差异 适用于 Java 的 AWS SDK](dynamodb-mapping-document-api.md)
+ [加密库迁移](ddb-encryption-lib-migrate.md)

# DynamoDB 映射 API 的版本 1 和版本 2 之间的区别 适用于 Java 的 AWS SDK
<a name="ddb-mapping"></a>

在的版本 1 和版本 2 之间，DynamoDB APIs 映射发生了显著变化。 适用于 Java 的 AWS SDK在版本 1 中，您可以使用`DynamoDBMapper`来处理 Java POJOs。在版本 2 中使用 `DynamoDbEnhancedClient`，该方法具有更新的方法名称、增强的架构定义选项和改进的类型安全性。

关键差异包括：
+ 新的方法名称（例如 `getItem`，而不使用 `load`）
+ 显式表架构创建
+ 同步和异步操作的内置支持
+ 空字符串和配置的处理方式发生了变化

本节介绍映射 API 更改、注释差异、配置更新和迁移指导，以协助您从 v1 `DynamoDBMapper` 转变到 v2 `DynamoDbEnhancedClient`。

**Contents**
+ [适用于 Java 的 SDK 版本 1 升级到版本 2 时，映射库发生的高级别更改](dynamodb-mapping-high-level.md)
  + [导入依赖项差异](dynamodb-mapping-high-level.md#dynamodb-mapping-deps)
+ [适用于 Java 的 SDK 版本 1 和版本 2 之间的 DynamoDB APIs 映射发生了变化](dynamodb-mapping-api-changes.md)
  + [创建客户端](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-client)
  + [建立到 DynamoDB 表/索引的映射](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-mapping)
  + [表操作](dynamodb-mapping-api-changes.md#dynamodb-mapping-api-changes-tobleops)
  + [映射类和属性](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas)
    + [bean 注释](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas-annos)
    + [V2 附加注释](dynamodb-mapping-api-changes.md#dynamodb-mapping-schemas-annos-v2-addnl)
  + [配置](dynamodb-mapping-api-changes.md#dynamodb-mapping-configuration)
    + [每个操作的配置](dynamodb-mapping-api-changes.md#dynamodb-mapping-configuration-per-op)
  + [条件](dynamodb-mapping-api-changes.md#dynamodb-mapping-conditionals)
  + [类型转换](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv)
    + [默认转换器](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-defaults)
    + [为属性设置自定义转换器](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-anno)
    + [添加类型转换器工厂或提供程序](dynamodb-mapping-api-changes.md#dynamodb-mapping-type-conv-factory)
+ [适用于 Java 的 SDK 版本 1 和版本 2 之间的字符串处理差异](dynamodb-migration-string-handling.md)
+ [适用于 Java 的 SDK 版本 1 和版本 2 之间的乐观锁差异](dynamodb-migrate-optimstic-locking.md)
+ [适用于 Java 的 SDK 版本 1 和版本 2 之间的 fluent setter 方法差异](dynamodb-migrate-fluent-setters.md)

# 适用于 Java 的 SDK 版本 1 升级到版本 2 时，映射库发生的高级别更改
<a name="dynamodb-mapping-high-level"></a>

在 V1 和 V2 中，每个库中映射客户端的名称不同：
+ V1-迪纳摩 DBMapper
+ V2 - DynamoDB 增强型客户端

您与这两个库的交互方式大致相同：实例化 a， mapper/client 然后为其提供一个 Java POJO，用于 APIs 读取这些项目并将其写入 DynamoDB 表。这两个库还为 POJO 的类提供了注释，以指导客户端如何处理 POJO。

迁移到 V2 时的显著差异包括：
+ V2 和 V1 为低级 DynamoDB 操作使用不同的方法名称。例如：    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/dynamodb-mapping-high-level.html)
+ V2 提供了多种定义表架构和映射 POJOs 到表格的方法。您可以选择使用注释或使用生成器从代码中生成的架构。V2 还提供架构的可变和不可变版本。
+ 在 V2 中，您需要在最初几个步骤中明确地创建表架构；而在 V1 中，根据需要从注释类中推断出表架构。
+ V2 在增强型客户端 API 中包括[文档 API 客户端](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html)，而 V1 则使用[单独的 API](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html)。
+ 在 V2 中，所有版本 APIs 均提供同步和异步版本。

有关 V2 增强型客户端的更多详细信息，请参阅本指南中的 [DynamoDB 映射部分](dynamodb-enhanced-client.md)。

## 导入依赖项差异
<a name="dynamodb-mapping-deps"></a>


| V1 | V2 | 
| --- | --- | 
|  <pre><dependencyManagement><br />  <dependencies><br />    <dependency><br />      <groupId>com.amazonaws</groupId><br />      <artifactId>aws-java-sdk-bom</artifactId><br />      <version>1.X.X</version><br />      <type>pom</type><br />      <scope>import</scope><br />    </dependency><br />  </dependencies><br /></dependencyManagement> <br /><br /><dependencies><br />  <dependency><br />    <groupId>com.amazonaws</groupId><br />    <artifactId>aws-java-sdk-dynamodb</artifactId><br />  </dependency><br /></dependencies></pre>  |  <pre><dependencyManagement><br />  <dependencies><br />    <dependency><br />      <groupId>software.amazon.awssdk</groupId><br />      <artifactId>bom</artifactId><br />      <version>2.X.X*</version><br />      <type>pom</type><br />      <scope>import</scope><br />    </dependency><br />  </dependencies><br /></dependencyManagement> <br /><br /><dependencies><br />  <dependency><br />    <groupId>software.amazon.awssdk</groupId><br />    <artifactId>dynamodb-enhanced</artifactId><br />  </dependency><br /></dependencies></pre>  | 

\$1 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

在 V1 中，单个依赖项包括低级 DynamoDB API 和 API，而在 V2 中，您可以使用构件依赖项来访问 mapping/document API。`dynamodb-enhanced` mapping/document `dynamodb-enhanced` 模块包含低级 `dynamodb` 模块的传递依赖项。

# 适用于 Java 的 SDK 版本 1 和版本 2 之间的 DynamoDB APIs 映射发生了变化
<a name="dynamodb-mapping-api-changes"></a>

## 创建客户端
<a name="dynamodb-mapping-api-changes-client"></a>


****  

| 使用案例 | V1 | V2 | 
| --- | --- | --- | 
|   正常实例化  |  <pre>AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard()<br />    .withCredentials(credentialsProvider)<br />    .withRegion(Regions.US_EAST_1)<br />    .build();<br />DynamoDBMapper mapper = new DynamoDBMapper(standardClient);</pre>  |  <pre>DynamoDbClient standardClient = DynamoDbClient.builder()<br />    .credentialsProvider(ProfileCredentialsProvider.create())<br />    .region(Region.US_EAST_1)<br />    .build();<br />DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()<br />    .dynamoDbClient(standardClient)<br />    .build();</pre>  | 
|   最小实例化  |  <pre>AmazonDynamoDB standardClient = AmazonDynamoDBClientBuilder.standard();<br />DynamoDBMapper mapper = new DynamoDBMapper(standardClient);</pre>  |  <pre>DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.create();</pre>  | 
|   带属性转换器\$1  |  <pre>DynamoDBMapper mapper = new DynamoDBMapper(standardClient, <br />                        attributeTransformerInstance);</pre>  |  <pre>DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()<br />    .dynamoDbClient(standardClient)<br />    .extensions(extensionAInstance, extensionBInstance)<br />    .build();</pre>  | 

\$1V2 中的扩展与 V1 中的属性转换器大致对应。[使用扩展自定义 DynamoDB 增强型客户端操作](ddb-en-client-extensions.md) 部分包含有关 V2 中扩展的更多信息。

## 建立到 DynamoDB 表/索引的映射
<a name="dynamodb-mapping-api-changes-mapping"></a>

在 V1 中，通过 bean 注释指定 DynamoDB 表名。在 V2 中，使用一种工厂方法 `table()` 来生成代表远程 DynamoDB 表的 `DynamoDbTable` 实例。`table()` 方法的第一个参数是 DynamoDB 表名。


****  

| 使用案例 | V1 | V2 | 
| --- | --- | --- | 
|   将 Java POJO 类映射到 DynamoDB 表  |  <pre>@DynamoDBTable(tableName ="Customer")<br />public class Customer {<br />  ...<br />}</pre>  |  <pre>DynamoDbTable<Customer> customerTable = enhancedClient.table("Customer",<br />    TableSchema.fromBean(Customer.class));</pre>  | 
|   映射到 DynamoDB 二级索引  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) 《DynamoDB 开发人员指南》中讨论 [V1 `query` 方法](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Methods.html#DynamoDBMapper.Methods.query)的部分展示了一个完整的示例。  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) 本指南中的 [使用二级索引](ddb-en-client-use-secindex.md) 部分提供了更多信息。  | 

## 表操作
<a name="dynamodb-mapping-api-changes-tobleops"></a>

本节介绍大多数标准用例中 V1 和 V2 之间存在差异的操作 APIs 。

在 V2 中，所有涉及单个表的操作都是在 `DynamoDbTable` 实例上调用，而不是在增强型客户端上调用。增强型客户端包含可以针对多个表的方法。

在下面名为*表操作*的表中，POJO 实例被称为 `item` 或称为某个具体类型（例如 `customer1`）。对于 V2 示例，名为 `table` 的实例是先前调用 `enhancedClient.table()` 的结果，该调用返回对 `DynamoDbTable` 实例的引用。

请注意，即使未显示，也可以使用 fluent 使用者模式调用大多数 V2 操作。例如，

```
Customer customer = table.getItem(r → r.key(key));
  or
Customer customer = table.getItem(r → r.key(k -> k.partitionValue("id").sortValue("email")))
```

对于 V1 操作，*表操作*（在下方）包含一些常用的表单，并未涵盖所有重载表单。例如，`load()` 方法有以下重载：

```
mapper.load(Customer.class, hashKey)
mapper.load(Customer.class, hashKey, rangeKey)
mapper.load(Customer.class, hashKey, config)
mapper.load(Customer.class, hashKey, rangeKey, config)
mapper.load(item)
mapper.load(item, config)
```

*表操作*（在下方）显示了常用的表单：

```
mapper.load(item)
mapper.load(item, config)
```


**表操作**  

| 使用案例 | V1 | V2 | 
| --- | --- | --- | 
|  将 Java POJO 写入 DynamoDB 表 **DynamoDB 操作**：`PutItem`，`UpdateItem`  |  <pre>mapper.save(item)<br />mapper.save(item, config)<br />mapper.save(item, saveExpression, config)</pre> 在 V1 中，`DynamoDBMapperConfig.SaveBehavior` 和注释决定了将调用哪个低级 DynamoDB 方法。通常，除非在使用 `SaveBehavior.CLOBBER` 和 `SaveBehavior.PUT`，否则会调用 `UpdateItem`。自动生成的密钥是一种特殊的使用案例，偶尔会同时使用 `PutItem` 和 `UpdateItem`。  |  <pre>table.putItem(putItemRequest)<br />table.putItem(item)<br />table.putItemWithResponse(item) //Returns metadata.<br /><br />updateItem(updateItemRequest)<br />table.updateItem(item)<br />table.updateItemWithResponse(item) //Returns metadata.</pre>  | 
|  从 DynamoDB 表中将项目读取到 Java POJO **DynamoDB 操作：**`GetItem`  |  <pre>mapper.load(item)<br />mapper.load(item, config)</pre>  |  <pre>table.getItem(getItemRequest)<br />table.getItem(item)<br />table.getItem(key)<br />table.getItemWithResponse(key) //Returns POJO with metadata.</pre>  | 
|  从 DynamoDB 表中删除项目 **DynamoDB 操作：**`DeleteItem`  |  <pre>mapper.delete(item, deleteExpression, config)</pre>  |  <pre>table.deleteItem(deleteItemRequest)<br />table.deleteItem(item)<br />table.deleteItem(key)</pre>  | 
|  查询 DynamoDB 表或二级索引并返回分页列表 **DynamoDB 操作：**`Query`  |  <pre>mapper.query(Customer.class, queryExpression)<br />mapper.query(Customer.class, queryExpression, <br />                             mapperConfig)</pre>  |  <pre>table.query(queryRequest)<br />table.query(queryConditional)</pre> 使用返回的 `PageIterable.stream()`（延迟加载）进行同步响应，使用 `PagePublisher.subscribe()` 进行异步响应  | 
|  查询 DynamoDB 表或二级索引并返回列表 **DynamoDB 操作：**`Query`  |  <pre>mapper.queryPage(Customer.class, queryExpression)<br />mapper.queryPage(Customer.class, queryExpression, <br />                                 mapperConfig)</pre>  |  <pre>table.query(queryRequest)<br />table.query(queryConditional)</pre> 使用返回的 `PageIterable.items()`（延迟加载）进行同步响应，使用 `PagePublisher.items.subscribe()` 进行异步响应  | 
|  扫描 DynamoDB 表或二级索引并返回分页列表 **DynamoDB 操作：**`Scan`  |  <pre>mapper.scan(Customer.class, scanExpression)<br />mapper.scan(Customer.class, scanExpression, <br />                            mapperConfig)</pre>  |  <pre>table.scan()<br />table.scan(scanRequest)</pre> 使用返回的 `PageIterable.stream()`（延迟加载）进行同步响应，使用 `PagePublisher.subscribe()` 进行异步响应  | 
|  扫描 DynamoDB 表或二级索引并返回列表 **DynamoDB 操作：**`Scan`  |  <pre>mapper.scanPage(Customer.class, scanExpression)<br />mapper.scanPage(Customer.class, scanExpression, <br />                                mapperConfig)</pre>  |  <pre>table.scan()<br />table.scan(scanRequest)</pre> 使用返回的 `PageIterable.items()`（延迟加载）进行同步响应，使用 `PagePublisher.items.subscribe()` 进行异步响应  | 
|  批量读取多个表中的多个项目 **DynamoDB 操作：**`BatchGetItem`  |  <pre>mapper.batchLoad(Arrays.asList(customer1, <br />                               customer2, <br />                               book1))<br />mapper.batchLoad(itemsToGet) <br />           // itemsToGet: Map<Class<?>, List<KeyPair>></pre>  |  <pre>enhancedClient.batchGetItem(batchGetItemRequest)<br /><br />enhancedClient.batchGetItem(r -> r.readBatches(<br />    ReadBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addGetItem(i -> i.key(k -> k.partitionValue(0)))<br />             .build(),<br />    ReadBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addGetItem(i -> i.key(k -> k.partitionValue(0)))<br />             .build()))<br /><br />// Iterate over pages with lazy loading or over all items <br />   from the same table.</pre>  | 
|  批量将多个项目写入多个表 **DynamoDB 操作：**`BatchWriteItem`  |  <pre>mapper.batchSave(Arrays.asList(customer1, <br />                               customer2, <br />                               book1)) </pre>  |  <pre>enhancedClient.batchWriteItem(batchWriteItemRequest)<br /><br />enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addPutItem(item1)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addPutItem(item2)<br />             .build()))</pre>  | 
|  批量删除多个表中的多个项目 **DynamoDB 操作：**`BatchWriteItem`  |  <pre>mapper.batchDelete(Arrays.asList(customer1, <br />                                 customer2, <br />                                 book1)) </pre>  |  <pre>enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addDeleteItem(item1key)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addDeleteItem(item2key)<br />             .build()))</pre>  | 
|  批量写入/删除多个项目 **DynamoDB 操作：**`BatchWriteItem`  |  <pre>mapper.batchWrite(Arrays.asList(customer1, book1), <br />                  Arrays.asList(customer2)) </pre>  |  <pre>enhancedClient.batchWriteItem(r -> r.writeBatches(<br />    WriteBatch.builder(Record1.class)<br />             .mappedTableResource(mappedTable1)<br />             .addPutItem(item1)<br />             .build(),<br />    WriteBatch.builder(Record2.class)<br />             .mappedTableResource(mappedTable2)<br />             .addDeleteItem(item2key)<br />             .build()))</pre>  | 
|  执行事务性写入 **DynamoDB 操作：**`TransactWriteItems`  |  <pre>mapper.transactionWrite(transactionWriteRequest)</pre>  |  <pre>enhancedClient.transactWriteItems(transasctWriteItemsRequest)</pre>  | 
|  执行事务性读取 **DynamoDB 操作：**`TransactGetItems`  |  <pre>mapper.transactionLoad(transactionLoadRequest)</pre>  |  <pre>enhancedClient.transactGetItems(transactGetItemsRequest) </pre>  | 
|  获取查询中匹配项的计数 **DynamoDB 操作：**使用 `Select.COUNT` 执行 `Query`  |  <pre>mapper.count(Customer.class, queryExpression)</pre>  |  <pre>// Get the count from query results.<br />PageIterable<Customer> pageIterable =<br />    customerTable.query(QueryEnhancedRequest.builder()<br />        .queryConditional(queryConditional)<br />        .select(Select.COUNT)<br />        .build());<br />Iterator<Page<Customer>> iterator = pageIterable.iterator();<br />Page<Customer> page = iterator.next();<br />int count = page.count();<br /><br />// For a more concise approach, you can chain the method calls:<br />int count = customerTable.query(QueryEnhancedRequest.builder()<br />                .queryConditional(queryConditional)<br />                .select(Select.COUNT)<br />                .build())<br />            .iterator().next().count();</pre>  | 
|  获取扫描中匹配项的计数 **DynamoDB 操作：**使用 `Select.COUNT` 执行 `Scan`  |  <pre>mapper.count(Customer.class, scanExpression)</pre>  |  <pre>// Get the count from scan results.<br />PageIterable<Customer> pageIterable =<br />    customerTable.scan(ScanEnhancedRequest.builder()<br />        .filterExpression(filterExpression)<br />        .select(Select.COUNT)<br />        .build());<br />Iterator<Page<Customer>> iterator = pageIterable.iterator();<br />Page<Customer> page = iterator.next();<br />int count = page.count();<br /><br />// For a more concise approach, you can chain the method calls:<br />int count = customerTable.scan(ScanEnhancedRequest.builder()<br />                .filterExpression(filterExpression)<br />                .select(Select.COUNT)<br />                .build())<br />            .iterator().next().count();</pre>  | 
|  在 DynamoDB 中创建与 POJO 类对应的表 **DynamoDB 操作：**`CreateTable`  |  <pre>mapper.generateCreateTableRequest(Customer.class)</pre> 前面的语句生成一个低级别的创建表请求；用户必须在 DynamoDB 客户端中调用 `createTable`。  |  <pre>table.createTable(createTableRequest)<br /><br />table.createTable(r -> r.provisionedThroughput(defaultThroughput())<br />    .globalSecondaryIndices(<br />        EnhancedGlobalSecondaryIndex.builder()<br />            .indexName("gsi_1")<br />            .projection(p -> p.projectionType(ProjectionType.ALL))<br />            .provisionedThroughput(defaultThroughput())<br />            .build()));</pre>  | 
|  在 DynamoDB 中执行并行扫描 **DynamoDB 操作：**使用 `Segment` 和 `TotalSegments` 参数执行 `Scan`  |  <pre>mapper.parallelScan(Customer.class, <br />                    scanExpression, <br />                    numTotalSegments)</pre>  |  用户需要处理工作线程并为每个分段调用 `scan`： <pre>table.scan(r -> r.segment(0).totalSegments(5))</pre>  | 
|  将 Amazon S3 与 DynamoDB 集成以存储智能 S3 链接  |  <pre>mapper.createS3Link(bucket, key)<br />mapper.getS3ClientCache()</pre>  |  不支持，因为它将 Amazon S3 与 DynamoDB 结合在一起。  | 

## 映射类和属性
<a name="dynamodb-mapping-schemas"></a>

在 V1 和 V2 中，都使用 bean 样式的注释将类映射到表。V2 还提供了[其他方法来为特定使用案例定义架构](ddb-en-client-adv-features.md#ddb-en-client-adv-features-schm-overview)，例如使用不可变类。

### bean 注释
<a name="dynamodb-mapping-schemas-annos"></a>

下表显示了 V1 和 V2 中使用的特定使用案例的等效 bean 注释。`Customer` 类场景用于说明参数。

V2 中的注释以及类和枚举遵循驼峰大小写惯例，使用 “” 而不是 “DynamoDB”。DynamoDb


| 使用案例 | V1 | V2 | 
| --- | --- | --- | 
| 将类映射到表 |  <pre>@DynamoDBTable (tableName ="CustomerTable")</pre>  | <pre>@DynamoDbBean<br />@DynamoDbBean(converterProviders = {...})</pre>表名在调用 DynamoDbEnhancedClient\$1table() 方法时定义。 | 
| 将类成员指定为表属性  |  <pre>@DynamoDBAttribute(attributeName = "customerName")</pre>  |  <pre>@DynamoDbAttribute("customerName") </pre>  | 
| 指定班级成员是 hash/partition 关键 |  <pre>@DynamoDBHashKey </pre>  |  <pre>@DynamoDbPartitionKey</pre>  | 
| 指定班级成员是 range/sort 关键 |  <pre>@DynamoDBRangeKey </pre>  |  <pre>@DynamoDbSortKey </pre>  | 
| 将类成员指定为二级索引哈希键/分区键 |  <pre>@DynamoDBIndexHashKey </pre>  |  <pre>@DynamoDbSecondaryPartitionKey </pre>  | 
| 将类成员指定为二级索引范围键/排序键 |  <pre>@DynamoDBIndexRangeKey </pre>  |  <pre>@DynamoDbSecondarySortKey </pre>  | 
| 映射到表时忽略此类成员 |  <pre>@DynamoDBIgnore </pre>  |  <pre>@DynamoDbIgnore</pre>  | 
| 将类成员指定为自动生成的 UUID 键属性 |  <pre>@DynamoDBAutoGeneratedKey</pre>  |  <pre>@DynamoDbAutoGeneratedUuid </pre> 默认情况下，不加载提供此功能的扩展；您必须将扩展添加到客户端生成器中。  | 
| 将类成员指定为自动生成的时间戳属性 |  <pre>@DynamoDBAutoGeneratedTimestamp</pre>  |  <pre>@DynamoDbAutoGeneratedTimestampAttribute</pre> 默认情况下，不加载提供此功能的扩展；您必须将扩展添加到客户端生成器中。  | 
| 将类成员指定为自动递增的版本属性 |  <pre>@DynamoDBVersionAttribute</pre>  |  <pre>@DynamoDbVersionAttribute</pre> 提供此功能的扩展会自动加载。  | 
| 将类成员指定为需要自定义转换 |  <pre>@DynamoDBTypeConverted</pre>  |  <pre>@DynamoDbConvertedBy</pre>  | 
| 将类成员指定为存储为另一个属性类型 |  <pre>@DynamoDBTyped(<DynamoDBAttributeType>)</pre>  |  使用 `AttributeConverter` 实现。V2 为常用 Java 类型提供许多内置转换器。您也可以实施自己的自定义 `AttributeConverter` 或 `AttributeConverterProvider`。请参阅本指南中的[控制属性转换](ddb-en-client-adv-features-conversion.md)。  | 
| 指定一个可以序列化为 DynamoDB 文档（JSON 风格的文档）或子文档的类  |  <pre>@DynamoDBDocument</pre>  | 使用增强型文档 API。请参阅以下资源：[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html) | 

### V2 附加注释
<a name="dynamodb-mapping-schemas-annos-v2-addnl"></a>


| 使用案例 | V1 | V2 | 
| --- | --- | --- | 
| 如果 Java 值为 null，则将类成员指定为不存储为 Null 属性 | 不适用 |  <pre>@DynamoDbIgnoreNulls</pre>  | 
| 如果所有属性都为 null，则将类成员指定为空对象 | 不适用 |  <pre>@DynamoDbPreserveEmptyObject</pre>  | 
| 为类成员指定特殊更新操作 | 不适用 |  <pre>@DynamoDbUpdateBehavior</pre>  | 
| 指定一个不可变类 | 不适用 |  <pre>@DynamoDbImmutable</pre>  | 
| 将类成员指定为自动递增的计数器属性 | 不适用 |  <pre>@DynamoDbAtomicCounter</pre> 提供此功能的扩展会自动加载。  | 

## 配置
<a name="dynamodb-mapping-configuration"></a>

在 V1 中，通常使用 `DynamoDBMapperConfig` 的实例来控制特定行为。您可以在创建映射器时或在发出请求时提供配置对象。在 V2 中，配置特定于操作的请求对象。


| 使用案例 | V1 | V1 中的默认设置 | V2 | 
| --- | --- | --- | --- | 
|  |  <pre>DynamoDBMapperConfig.builder()</pre>  |  |  | 
| Batch load/write 重试策略 |  <pre>  .withBatchLoadRetryStrategy(loadRetryStrategy)</pre> <pre>  .withBatchWriteRetryStrategy(writeRetryStrategy)</pre>  | 重试失败的项目 | 在底层 DynamoDBClient 中配置重试策略。请参阅本指南中的[在中配置重试行为 AWS SDK for Java 2.x](retry-strategy.md)。 | 
| 一致性读取 |  <pre>  .withConsistentReads(CONSISTENT)</pre>  | EVENTUAL | 默认情况下，读取操作的一致性读取为 false。在请求对象上使用 .consistentRead(true) 覆盖。 | 
| 包含编组器/解组器集合的转换架构 |  <pre>  .withConversionSchema(conversionSchema)</pre> 静态实现与旧版本向后兼容。  | V2\$1COMPATIBLE | 不适用。这是一项遗留特性，指的是 DynamoDB 的最早版本（V1）存储数据类型的方式，而在增强型客户端中不再保留此行为。DynamoDB V1 中的一个行为示例是将布尔值存储为数字而不是布尔值。 | 
| 表名称 |  <pre>  .withObjectTableNameResolver()<br />  .withTableNameOverride() <br />  .withTableNameResolver()</pre> 静态实现与旧版本向后兼容  | 使用注释或根据类来推断 |  表名在调用 `DynamoDbEnhancedClient#table()` 方法时定义。  | 
| 分页加载策略 |  <pre>  .withPaginationLoadingStrategy(strategy)</pre>  选项包括：LAZY\$1`LOADING`、`EAGER_LOADING` 或 `ITERATION_ONLY`  | LAZY\$1LOADING |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/dynamodb-mapping-api-changes.html)  | 
| 请求指标收集 |  <pre>  .withRequestMetricCollector(collector)</pre>  | null | 在构建标准 DynamoDB 客户端时在 ClientOverrideConfiguration 中使用 metricPublisher()。 | 
| 保存行为 |  <pre>  .withSaveBehavior(SaveBehavior.CLOBBER) </pre> 选项包括 `UPDATE`、`CLOBBER`、`PUT`、`APPEND_SET` 或 `UPDATE_SKIP_NULL_ATTRIBUTES`。  | UPDATE |  在 V2 中，您可以显式调用 `putItem()` 或 `updateItem()`。 `CLOBBER or PUT`：V2 中的相应动作是调用 `putItem()`。没有特定的 `CLOBBER` 配置。 `UPDATE`: 对应于 `updateItem()` `UPDATE_SKIP_NULL_ATTRIBUTES`: 对应于`updateItem()`。使用请求设置 `ignoreNulls` 和注释/标签 `DynamoDbUpdateBehavior` 控制更新行为。 `APPEND_SET`：不支持  | 
| 类型转换器工厂 |  <pre>  .withTypeConverterFactory(typeConverterFactory) </pre>  | 标准类型转换器 |  使用以下方式在 bean 上设置 <pre>@DynamoDbBean(converterProviders = {ConverterProvider.class, <br />        DefaultAttributeConverterProvider.class})</pre>  | 

### 每个操作的配置
<a name="dynamodb-mapping-configuration-per-op"></a>

在 V1 中，某些操作（例如 `query()`）可以通过提交给操作的“表达式”对象来进行高度灵活的配置。例如：

```
DynamoDBQueryExpression<Customer> emailBwQueryExpr = new DynamoDBQueryExpression<Customer>()
    .withRangeKeyCondition("Email",
        new Condition()
            .withComparisonOperator(ComparisonOperator.BEGINS_WITH)
            .withAttributeValueList(
                new AttributeValue().withS("my")));

mapper.query(Customer.class, emailBwQueryExpr);
```

在 V2 中，不使用配置对象，而是使用生成器对请求对象设置参数。例如：

```
QueryEnhancedRequest emailBw = QueryEnhancedRequest.builder()
    .queryConditional(QueryConditional
        .sortBeginsWith(kb -> kb
            .sortValue("my"))).build();

customerTable.query(emailBw);
```

## 条件
<a name="dynamodb-mapping-conditionals"></a>

在 V2 中，条件表达式和筛选表达式使用 `Expression` 对象来表达，该对象封装了条件以及名称和筛选条件的映射。


| 使用案例 | 操作 | V1 | V2 | 
| --- | --- | --- | --- | 
| 预期的属性条件 | save()、delete()、query()、scan() |  <pre>new DynamoDBSaveExpression()<br />  .withExpected(Collections.singletonMap(<br />      "otherAttribute", new ExpectedAttributeValue(false)))<br />  .withConditionalOperator(ConditionalOperator.AND);</pre>  | 已弃用；改用 ConditionExpression。 | 
| 条件表达式 | delete() |  <pre>deleteExpression.setConditionExpression("zipcode = :zipcode")<br />deleteExpression.setExpressionAttributeValues(...)<br /></pre>  |  <pre>Expression conditionExpression =<br />    Expression.builder()<br />        .expression("#key = :value OR #key1 = :value1")<br />        .putExpressionName("#key", "attribute")<br />        .putExpressionName("#key1", "attribute3")<br />        .putExpressionValue(":value", AttributeValues.stringValue("wrong"))<br />        .putExpressionValue(":value1", AttributeValues.stringValue("three"))<br />        .build();<br /><br />DeleteItemEnhancedRequest request = DeleteItemEnhancedRequest.builder()<br />         .conditionExpression(conditionExpression).build();</pre>  | 
| 筛选表达式 | query()、scan() |  <pre>scanExpression<br />  .withFilterExpression("#statename = :state")<br />  .withExpressionAttributeValues(attributeValueMapBuilder.build())<br />  .withExpressionAttributeNames(attributeNameMapBuilder.build())<br /></pre>  |  <pre>Map<String, AttributeValue> values = singletonMap(":key", stringValue("value"));<br />Expression filterExpression =<br />    Expression.builder()<br />        .expression("name = :key")<br />        .expressionValues(values)<br />        .build();<br />QueryEnhancedRequest request = QueryEnhancedRequest.builder()<br />    .filterExpression(filterExpression).build();<br /></pre>  | 
| 查询的条件表达式 | query() |  <pre>queryExpression.withKeyConditionExpression()</pre>  |  <pre>QueryConditional keyEqual = QueryConditional.keyEqualTo(b -> b<br />                .partitionValue("movie01"));<br /><br />QueryEnhancedRequest tableQuery = QueryEnhancedRequest.builder()<br />                .queryConditional(keyEqual)<br />                .build();</pre>  | 

## 类型转换
<a name="dynamodb-mapping-type-conv"></a>

### 默认转换器
<a name="dynamodb-mapping-type-conv-defaults"></a>

在 V2 中，SDK 为所有常见类型提供了一组默认转换器。既可以在整体提供程序级别更改类型转换器，也可以为单个属性更改类型转换器。您可以在 [AttributeConverter](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/AttributeConverter.html)API 参考中找到可用转换器的列表。

### 为属性设置自定义转换器
<a name="dynamodb-mapping-type-conv-anno"></a>

在 V1 中，您可以使用 `@DynamoDBTypeConverted` 对 getter 方法添加注释，以指定在 Java 属性类型和 DynamoDB 属性类型之间进行转换的类。例如，`CurrencyFormatConverter` 可以在 Java `Currency` 类型和 DynamoDB 字符串之间应用转换，如以下代码段所示。

```
@DynamoDBTypeConverted(converter = CurrencyFormatConverter.class)
public Currency getCurrency() { return currency; }
```

上一个代码段的 V2 等效代码如下所示。

```
@DynamoDbConvertedBy(CurrencyFormatConverter.class)
public Currency getCurrency() { return currency; }
```

**注意**  
在 V1 中，您可以将注释应用于属性本身、类型或用户定义的注释，V2 仅支持将注释应用于 getter。

### 添加类型转换器工厂或提供程序
<a name="dynamodb-mapping-type-conv-factory"></a>

在 V1 中，您可以提供自己的类型转换器集，也可以通过在配置中添加类型转换器工厂来覆盖您在意的类型。类型转换器工厂扩展 `DynamoDBTypeConverterFactory`，通过获取对默认集的引用并对其进行扩展来完成覆盖。以下代码段演示了如何执行此操作。

```
DynamoDBTypeConverterFactory typeConverterFactory =
    DynamoDBTypeConverterFactory.standard().override()
        .with(String.class, CustomBoolean.class, new DynamoDBTypeConverter<String, CustomBoolean>() {
            @Override
            public String convert(CustomBoolean bool) {
                return String.valueOf(bool.getValue());
            }
            @Override
            public CustomBoolean unconvert(String string) {
                return new CustomBoolean(Boolean.valueOf(string));
            }}).build();
DynamoDBMapperConfig config =
    DynamoDBMapperConfig.builder()
        .withTypeConverterFactory(typeConverterFactory)
        .build();
DynamoDBMapper mapperWithTypeConverterFactory = new DynamoDBMapper(dynamo, config);
```

V2 通过 `@DynamoDbBean` 注释提供了类似的功能。您可以提供单个 `AttributeConverterProvider` 或一个有序的 `AttributeConverterProvider` 链。请注意，如果您提供自己的属性转换器提供程序链，则将覆盖默认的转换器提供程序，且必须在链中包括它才能使用其属性转换器。

```
@DynamoDbBean(converterProviders = {
   ConverterProvider1.class, 
   ConverterProvider2.class,
   DefaultAttributeConverterProvider.class})
public class Customer {
  ...
}
```

本指南中关于[属性转换](ddb-en-client-adv-features-conversion.md#ddb-en-client-adv-features-conversion-example)的部分包含了 V2 的完整示例。

# 适用于 Java 的 SDK 版本 1 和版本 2 之间的字符串处理差异
<a name="dynamodb-migration-string-handling"></a>

向 DynamoDB 发送数据时，V1 和 V2 对空字符串的处理方式有所不同：
+ **V1**：在发送到 DynamoDB 之前将空字符串转换为 null 值（导致没有属性）
+ **V2**：将空字符串作为实际的空字符串值发送给 DynamoDB

**重要**  
迁移到 V2 后，如果您不想在 DynamoDB 中存储空字符串，则必须实施自定义转换器。如果没有自定义转换器，V2 会将空字符串作为实际的空字符串属性存储在 DynamoDB 项目中，这与 V1 完全省略这些属性的行为不同。

**Example V2 的自定义转换器，用于将空字符串属性转换为 null**  

```
/**
 * Custom converter that maintains V1 behavior by converting empty strings to null values
 * when writing to DynamoDB, ensuring compatibility with existing data. No attribute will be saved to DynamoDB.
 */
public class NullifyEmptyStringConverter implements AttributeConverter<String> {
    @Override
    public AttributeValue transformFrom(String value) {
        if (value == null || value.isEmpty()) {
            return AttributeValue.builder().nul(true).build();
        }
        return AttributeValue.builder().s(value).build();
    }

    @Override
    public String transformTo(AttributeValue attributeValue) {
        if (attributeValue.nul()) {
            return null;
        }
        return attributeValue.s();
    }

    @Override
    public EnhancedType<String> type() {
        return EnhancedType.of(String.class);
    }

    @Override
    public AttributeValueType attributeValueType() {
        return AttributeValueType.S;
    }
}

// V2 usage:
@DynamoDbBean
public class Customer {
    private String name;

    @DynamoDbConvertedBy(NullifyEmptyStringConverter.class)
    public String getName() {
        return name;
    }
}
```



# 适用于 Java 的 SDK 版本 1 和版本 2 之间的乐观锁差异
<a name="dynamodb-migrate-optimstic-locking"></a>

V1 和 V2 都使用属性注释来实施乐观锁，注释在 bean 类上标记一个属性以存储版本号。


**乐观锁行为的差异**  

|  | V1 | V2 | 
| --- | --- | --- | 
| bean 类注释 | @DynamoDBVersionAttribute | @DynamoDbVersionAttribute（请注意，V2 使用小写的“b”） | 
| 初始保存 | 版本号属性设置为 1。 |  使用 `@DynamoDbVersionAttribute(startAt = X)` 设置的版本属性的起始值。默认值为 0。  | 
| 更新 | 如果条件检查确认正在更新的对象的版本号与数据库中的版本号相匹配，则版本号属性将增加 1。 |  如果条件检查确认正在更新的对象的版本号与数据库中的版本号相匹配，则版本号属性会递增。 按照使用 `@DynamoDbVersionAttribute(incrementBy = X)` 设置的 `incrementBy` 选项来增加版本号属性。默认值为 1。  | 
| 删除 | DynamoDBMapper 添加条件检查，以确认要删除的对象的版本号与数据库中的版本号相匹配。 |  V2 不会自动为删除操作添加条件。如果要控制删除行为，则必须手动添加条件表达式。 在以下示例中，`recordVersion` 是 bean 的版本属性。 <pre>// 1. Read the item and get its current version.<br />Customer item = customerTable.getItem(Key.builder().partitionValue("someId").build());<br />AttributeValue currentVersion = item.getRecordVersion();<br /><br />// 2. Create conditional delete with the `currentVersion` value.<br />DeleteItemEnhancedRequest deleteItemRequest =<br />    DeleteItemEnhancedRequest.builder()<br />       .key(KEY)<br />       .conditionExpression(Expression.builder()<br />           .expression("recordVersion = :current_version_value")<br />           .putExpressionValue(":current_version_value", currentVersion)<br />           .build()).build();<br /><br />customerTable.deleteItem(deleteItemRequest);</pre>  | 
| 带条件检查的事务写入 | 您不能使用在 addConditionCheck 方法中用 @DynamoDBVersionAttribute 进行注释的 bean 类。 | 您可以在 addConditionCheck 生成器方法中通过 @DynamoDbVersionAttribute 注释为 transactWriteItems 请求使用 bean 类。 | 
| 禁用 | 通过将  DynamoDBMapperConfig.SaveBehavior 枚举值从 UPDATE 更改为 CLOBBER 来禁用乐观锁。 |  不使用 `@DynamoDbVersionAttribute` 注释。  | 

# 适用于 Java 的 SDK 版本 1 和版本 2 之间的 fluent setter 方法差异
<a name="dynamodb-migrate-fluent-setters"></a>

你可以在 V1 的 DynamoDB 映射 API 中使用 POJOs 流畅的设置器，也可以在 2.30.29 版本之后的 V2 中使用。

例如，以下 POJO 通过 `setName` 方法返回一个 `Customer` 实例：

```
// V1

@DynamoDBTable(tableName ="Customer")
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){
     this.name = name;
     return this;
  }
}
```

但是，如果您使用的是 2.30.29 之前的 V2 版本，则 `setName` 会返回 `Customer` 实例，其 `name` 值为 `null`。

```
// V2 prior to version 2.30.29.

@DynamoDbBean
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){ 
     this.name = name;
     return this;  // Bug: returns this instance with a `name` value of `null`.
  }
}
```

```
// Available in V2 since version 2.30.29.

@DynamoDbBean
public class Customer{
  private String name;
  // Other attributes and methods not shown.
  public Customer setName(String name){ 
     this.name = name;
     return this;  // Returns this instance for method chaining with the `name` value set.
  }
}
```

# 文档 API 的版本 1 和版本 2 之间的差异 适用于 Java 的 AWS SDK
<a name="dynamodb-mapping-document-api"></a>

文档 API 支持将 JSON 风格的文档作为 DynamoDB 表中的单个项目来处理。V1 文档 API 在 V2 中有对应的 API，但是 V2 没有像 V1 那样为文档 API 使用单独的客户端，而是在 DynamoDB 增强型客户端中整合了文档 API 功能。

在 V1 中，[https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Item.html](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Item.html) 类代表来自 DynamoDB 表的非结构化记录。在 V2 中，非结构化记录由 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html) 类的实例表示。请注意，在 V2 中，主键在表架构中定义，在 V1 中，主键在项目本身定义。

下表比较了 V1 和 V2 APIs 中文档之间的差异。


| 使用案例 | V1 | V2 | 
| --- |--- |--- |
| 创建文档客户端 |  <pre>AmazonDynamoDB client = ... //Create a client.<br />DynamoDB documentClient = new DynamoDB(client);</pre>  |  <pre>// The V2 Document API uses the same DynamoDbEnhancedClient<br />// that is used for mapping POJOs.<br />DynamoDbClient standardClient = ... //Create a standard client.<br />DynamoDbEnhancedClient enhancedClient = ... // Create an enhanced client.<br /></pre>  | 
| 引用表格 |  <pre>Table documentTable = docClient.documentClient("Person");</pre>  |  <pre>DynamoDbTable<EnhancedDocument> documentTable = enhancedClient.table("Person",  <br />        TableSchema.documentSchemaBuilder()<br />              .addIndexPartitionKey(TableMetadata.primaryIndexName(),"id", AttributeValueType.S)<br />              .attributeConverterProviders(AttributeConverterProvider.defaultProvider())<br />              .build());</pre>  | 
| **Work with semi-structured data** | 
| --- |
| 放置项目 |  <pre>Item item = new Item()<br />      .withPrimaryKey("id", 50)<br />      .withString("firstName", "Shirley");<br />PutItemOutcome outcome = documentTable.putItem(item);</pre>  |  <pre>EnhancedDocument personDocument = EnhancedDocument.builder()<br />        .putNumber("id", 50)<br />        .putString("firstName", "Shirley")<br />        .build();<br />documentTable.putItem(personDocument);</pre>  | 
| 获取项目 |  <pre>GetItemOutcome outcome = documentTable.getItemOutcome( "id", 50);<br />Item personDocFromDb = outcome.getItem();<br />String firstName = personDocFromDb.getString("firstName");<br /></pre>  |  <pre>EnhancedDocument personDocFromDb = documentTable<br />        .getItem(Key.builder()<br />            .partitionValue(50)<br />            .build()); <br />String firstName = personDocFromDb.getString("firstName");<br /></pre>  | 
| **Work with JSON items** | 
| --- |
| 转换 JSON 结构以将其与文档 API 配合使用 |  <pre>// The 'jsonPerson' identifier is a JSON string. <br />Item item = new Item().fromJSON(jsonPerson);</pre>  |  <pre>// The 'jsonPerson' identifier is a JSON string.<br />EnhancedDocument document = EnhancedDocument.builder()<br />        .json(jsonPerson).build());</pre>  | 
| 把 JSON |  <pre>documentTable.putItem(item)</pre>  |  <pre>documentTable.putItem(document);</pre>  | 
| 阅读 JSON |  <pre>GetItemOutcome outcome = //Get item.<br />String jsonPerson = outcome.getItem().toJSON();</pre>  |  <pre>String jsonPerson = documentTable.getItem(Key.builder()<br />        .partitionValue(50).build())<br />        .fromJson();</pre>  | 

## API 参考和文档指南 APIs
<a name="dynamodb-mapping-document-api-ref"></a>


|  | V1 | V2 | 
| --- | --- | --- | 
| API 参考 | [API 参考](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/package-summary.html) | [API 参考](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) | 
| 文档指南 | [Amazon DynamoDB 开发人员指南](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/JavaDocumentAPIItemCRUD.html) | [增强型文档 API](ddb-en-client-doc-api.md)（本指南） | 

# V1 Xpec API 到 V2 表达式 API
<a name="ddb-v1-xspec-migrate"></a>

V1 中提供的表达式规范（Xspec）API 协助创建用于处理面向文档的数据的表达式，该 API 在 V2 中不可用。V2 使用 Expression API，它可以处理面向文档的数据和映射的数据。 object-to-item


****  

|  | V1 | V2 | 
| --- | --- | --- | 
| API 名称 | 表达式规范（Xspec）API | 表达式 API | 
| 结合使用 | 文档 API [表](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Table.html)类的方法，例如 [updateItem](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Table.html#updateItem-java.lang.String-java.lang.Object-com.amazonaws.services.dynamodbv2.xspec.UpdateItemExpressionSpec-) 和 [scan](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Table.html#scan-com.amazonaws.services.dynamodbv2.xspec.ScanExpressionSpec-) |  两个 APIs DynamoDB 增强版客户端： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/ddb-v1-xspec-migrate.html) 对于这两种类型 APIs，在您获取[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)实例之后： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/ddb-v1-xspec-migrate.html) 创建请求对象时，在 `DynamoDbTable` 方法中使用表达式。例如，在 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryEnhancedRequest.Builder.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/model/QueryEnhancedRequest.Builder.html) 的 `filterExpression` 方法中  | 
| 资源 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/sdk-for-java/latest/developer-guide/ddb-v1-xspec-migrate.html)  | 本 Java 开发人员指南中的[表达式信息](ddb-en-client-expressions.md) | 

# 加密库迁移
<a name="ddb-encryption-lib-migrate"></a>

有关迁移 DynamoDB 加密库以与 Java SDK 的 V2 配合使用的信息，请参阅《[Amazon DynamoDB Encryption Client 开发人员指南](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/ddb-java-migrate.html)》。

# Amazon SQS 请求批处理从版本 1 到版本 2 的更改
<a name="migration-sqs-auto-batching"></a>

本主题详细介绍了 适用于 Java 的 AWS SDK版本 1 和版本 2 之间的 Amazon SQS 自动请求批处理的更改。

## 高级别更改
<a name="migration-sqs-auto-batching-high-level-changes"></a>

 适用于 Java 的 AWS SDK 1.x 使用单独的类执行客户端缓冲，该`[AmazonSQSBufferedAsyncClient](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/sqs/buffered/AmazonSQSBufferedAsyncClient.html)`类需要显式初始化才能进行请求批处理。

使用 AWS SDK for Java 2.x 简化并增强了缓冲功能。`[SqsAsyncBatchManager](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html)`该接口的实现提供了直接与标准 `[SqsAsyncClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/SqsAsyncClient.html)` 集成的自动请求批处理功能。要了解 v2 的 `SqsAsyncBatchManager`，请参阅本指南中的 [将 Amazon SQS 的自动请求批处理与 AWS SDK for Java 2.x](sqs-auto-batch.md) 主题。


| 更改 | v1 |  v2 | 
| --- | --- | --- | 
|    Maven 依赖项  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>com.amazonaws</groupId><br />            <artifactId>aws-java-sdk-bom</artifactId><br />            <version>1.12.7821</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>com.amazonaws</groupId><br />        <artifactId>aws-java-sdk-sqs</artifactId><br />    </dependency><br /></dependencies><br /></pre>  |  <pre><dependencyManagement><br />    <dependencies><br />        <dependency><br />            <groupId>software.amazon.awssdk</groupId><br />            <artifactId>bom</artifactId><br />            <version>2.31.152</version><br />            <type>pom</type><br />            <scope>import</scope><br />        </dependency><br />    </dependencies><br /></dependencyManagement><br /><dependencies><br />    <dependency><br />        <groupId>software.amazon.awssdk</groupId><br />        <artifactId>sqs</artifactId><br />    </dependency><br /></dependencies></pre>  | 
| 软件包名称 | com.amazonaws.services.sqs.buffered | software.amazon.awssdk.services.sqs.batchmanager | 
| 类名 |  `[AmazonSQSBufferedAsyncClient](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/sqs/buffered/AmazonSQSBufferedAsyncClient.html)`  | [SqsAsyncBatchManager](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sqs/batchmanager/SqsAsyncBatchManager.html) | 

1 [最新版本](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom)。2 [最新版本](https://central.sonatype.com/artifact/software.amazon.awssdk/bom)。

## 使用 SQS 自动请求批处理
<a name="migration-sqs-auto-batching-using"></a>


| 更改 | v1 |  v2 | 
| --- | --- | --- | 
| 创建批量管理器 |  <pre>AmazonSQSAsync sqsAsync = new AmazonSQSAsyncClient();<br />AmazonSQSAsync bufferedSqs = new <br />            AmazonSQSBufferedAsyncClient(sqsAsync);</pre>  |  <pre>SqsAsyncClient asyncClient = SqsAsyncClient.create();<br />SqsAsyncBatchManager sqsAsyncBatchManager = <br />            asyncClient.batchManager();</pre>  | 
| 使用自定义配置创建批量管理器 |  <pre>AmazonSQSAsync sqsAsync = new AmazonSQSAsyncClient();<br /><br />QueueBufferConfig queueBufferConfig = new QueueBufferConfig()<br />        .withMaxBatchOpenMs(200)<br />        .withMaxBatchSize(10)<br />        .withMinReceiveWaitTimeMs(1000)<br />        .withVisibilityTimeoutSeconds(20)<br />        .withReceiveMessageAttributeNames(messageAttributeValues);<br /><br />AmazonSQSAsync bufferedSqs = <br />        new AmazonSQSBufferedAsyncClient(sqsAsync, queueBufferConfig);</pre>  |  <pre>BatchOverrideConfiguration batchOverrideConfiguration = <br />    BatchOverrideConfiguration.builder()<br />        .sendRequestFrequency(Duration.ofMillis(200))<br />        .maxBatchSize(10)<br />        .receiveMessageMinWaitDuration(Duration.ofMillis(1000))<br />        .receiveMessageVisibilityTimeout(Duration.ofSeconds(20))<br />        .receiveMessageSystemAttributeNames(messageSystemAttributeNames)<br />        .receiveMessageAttributeNames(messageAttributeValues)<br />        .build();<br /><br />SqsAsyncBatchManager sqsAsyncBatchManager = SqsAsyncBatchManager.builder()<br />        .overrideConfiguration(batchOverrideConfiguration)<br />        .client(SqsAsyncClient.create())<br />        .scheduledExecutor(Executors.newScheduledThreadPool(8))<br />        .build();</pre>  | 
| 发送消息 |  <pre>Future<SendMessageResult> sendResultFuture = <br />        bufferedSqs.sendMessageAsync(new SendMessageRequest()<br />                .withQueueUrl(queueUrl)<br />                .withMessageBody(body));</pre>  |  <pre>CompletableFuture<SendMessageResponse> sendCompletableFuture = <br />        sqsAsyncBatchManager.sendMessage(<br />                SendMessageRequest.builder()<br />                        .queueUrl(queueUrl)<br />                        .messageBody(body)<br />                        .build());</pre>  | 
| 删除消息 |  <pre>Future<DeleteMessageResult> deletResultFuture =<br />        bufferedSqs.deleteMessageAsync(new DeleteMessageRequest()<br />                .withQueueUrl(queueUrl));</pre>  |  <pre>CompletableFuture<DeleteMessageResponse> deleteResultCompletableFuture<br />        = sqsAsyncBatchManager.deleteMessage(<br />                DeleteMessageRequest.builder()<br />                        .queueUrl(queueUrl)<br />                        .build());</pre>  | 
| 更改消息的可见性 |  <pre>Future<ChangeMessageVisibilityResult> changeVisibilityResultFuture =<br />        bufferedSqs.changeMessageVisibilityAsync<br />                (new ChangeMessageVisibilityRequest()<br />                        .withQueueUrl(queueUrl)<br />                        .withVisibilityTimeout(20));</pre>  |  <pre>CompletableFuture<ChangeMessageVisibilityResponse> changeResponseCompletableFuture<br />        = sqsAsyncBatchManager.changeMessageVisibility(<br />                ChangeMessageVisibilityRequest.builder()<br />                        .queueUrl(queueUrl)<br />                        .visibilityTimeout(20)<br />                        .build());</pre>  | 
| 接收消息 |  <pre>ReceiveMessageResult receiveResult =<br />        bufferedSqs.receiveMessage(<br />                new ReceiveMessageRequest()<br />                        .withQueueUrl(queueUrl));</pre>  |  <pre>CompletableFuture<ReceiveMessageResponse> <br />        responseCompletableFuture = sqsAsyncBatchManager.receiveMessage(<br />                ReceiveMessageRequest.builder()<br />                        .queueUrl(queueUrl)<br />                        .build());</pre>  | 

## 异步返回类型差异
<a name="migration-sqs-auto-batching-asyc-return-type"></a>


| 更改 | v1 |  v2 | 
| --- | --- | --- | 
| 返回类型 | Future<ResultType> | CompletableFuture<ResponseType> | 
| 回调机制 | 使用单独的 onSuccess 和 onError 方法需要 AsyncHandler | JDK CompletableFuture APIs 提供的用途，例如whenComplete()、、thenCompose() thenApply() | 
| 异常处理 | 使用 AsyncHandler\$1onError() 方法 | JDK CompletableFuture APIs 提供的用途，例如exceptionally()handle()、或 whenComplete() | 
| 取消 | 通过 Future.cancel() 实现基本支持 | 取消父 CompletableFuture 会自动取消链中的所有相关 Future | 

## 异步完成处理差异
<a name="migration-sqs-auto-batching-asyc-completion-handling"></a>


| 更改 | v1 |  v2 | 
| --- | --- | --- | 
| 响应处理程序实现 |  <pre>Future<ReceiveMessageResult> future = bufferedSqs.receiveMessageAsync(<br />        receiveRequest,<br />        new AsyncHandler<ReceiveMessageRequest, ReceiveMessageResult>() {<br />            @Override<br />            public void onSuccess(ReceiveMessageRequest request, <br />                              ReceiveMessageResult result) {<br />                List<Message> messages = result.getMessages();<br />                System.out.println("Received " + messages.size() + " messages");<br />                for (Message message : messages) {<br />                    System.out.println("Message ID: " + message.getMessageId());<br />                    System.out.println("Body: " + message.getBody());<br />                }<br />            }<br /><br />            @Override<br />            public void onError(Exception e) {<br />                System.err.println("Error receiving messages: " + e.getMessage());<br />                e.printStackTrace();<br />            }<br />        }<br />);</pre>  |  <pre>CompletableFuture<ReceiveMessageResponse> completableFuture = sqsAsyncBatchManager<br />               .receiveMessage(ReceiveMessageRequest.builder()<br />               .queueUrl(queueUrl).build())<br />        .whenComplete((receiveMessageResponse, throwable) -> {<br />            if (throwable != null) {<br />                System.err.println("Error receiving messages: " + throwable.getMessage());<br />                throwable.printStackTrace();<br />            } else {<br />                List<Message> messages = receiveMessageResponse.messages();<br />                System.out.println("Received " + messages.size() + " messages");<br />                for (Message message : messages) {<br />                    System.out.println("Message ID: " + message.messageId());<br />                    System.out.println("Body: " + message.body());<br />                }<br />            }<br />        });</pre>  | 

## 关键配置参数
<a name="migration-sqs-auto-batching-params"></a>


****  

| 参数 | v1 |  v2 | 
| --- | --- | --- | 
| 最大批次大小 | maxBatchSize（每批默认为 10 个请求） | maxBatchSize（每批默认为 10 个请求） | 
| 批次等待时间 | maxBatchOpenMs（默认值为 200 毫秒） | sendRequestFrequency（默认值为 200 毫秒） | 
| 可见性超时 | visibilityTimeoutSeconds（队列默认值为 -1） | receiveMessageVisibilityTimeout（队列默认值） | 
| 最小等待时间 | longPollWaitTimeoutSeconds（如果 longPoll 为 true，则为 20 秒） | receiveMessageMinWaitDuration（默认值为 50 毫秒） | 
| 消息属性 | 使用 ReceiveMessageRequest 进行设置 | receiveMessageAttributeNames（默认值为无） | 
| 系统属性 | 使用 ReceiveMessageRequest 进行设置 | receiveMessageSystemAttributeNames（默认值为无） | 
| 长轮询 | longPoll（默认值为 true） | 不支持，以便避免让已建立的连接一直处于等待状态，直到服务器发送消息 | 
| 长时间轮询的最长等待时间 | longPollWaitTimeoutSeconds（默认值为 20 秒） | 不支持，以便避免让已建立的连接一直处于等待状态，直到服务器发送消息 | 
| 在客户端预取和存储接收批次的最大数量 | maxDoneReceiveBatches（10 个批次） | 不支持，因为这在内部处理 | 
| 同时处理的最大活动出站批次数量 | maxInflightOutboundBatches（默认为 5 个批次） | 不支持，因为这在内部处理 | 
| 同时处理的最大活动接收批次数量 | maxInflightReceiveBatches（默认为 10 个批次） | 不支持，因为这在内部处理 | 