带示例的迁移 step-by-step 说明 - Amazon SDK for Java 2.x
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

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

带示例的迁移 step-by-step 说明

本节提供了将当前使用适用于 Java 的 SDK v1.x 的应用程序迁移到适用于 Java 2.x 的 SDK 的 step-by-step 指南。第一部分概述了各个步骤,然后是迁移的详细示例。

此处介绍的步骤描述了正常用例的迁移,即应用程序 Amazon Web Services 使用模型驱动的服务客户端进行调用。如果您需要迁移使用更高级别 API(例如 S3 传输管理器CloudFront预签名)的代码,请参阅Amazon SDK for Java 1.x 和 2.x 有什么区别目录下的部分。

此处描述的方法是一个建议。您可以使用其他技术并利用 IDE 的代码编辑功能来获得相同的结果。

步骤概述

1. 首先添加适用于 Java 的 SDK 2.x BOM

通过将适用于 Java SDK 2.x 的 Maven BOM(物料清单)元素添加到您的 POM 文件中,可以确保所需的所有版本 2 依赖项都来自同一个版本。你的 POM 可以同时包含 v1 和 v2 的依赖关系。这允许您以增量方式迁移代码,而不是一次全部更改。

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

您可以在 Maven 中央存储库中找到最新版本

2. 在文件中搜索 v1 类的导入语句

通过扫描应用程序中的文件以查找 v1 导入中使用的 service_ID,你会发现所使用的唯一服务 ID。SERVICE_ID 是一个简短、唯一的名称。 Amazon Web Service例如,亚马逊 Co cognitoidentity gnito Identity 的 SERVICE_ID。

3. 从 v1 的导入语句中确定 v2 Maven 的依赖关系

找到所有唯一的 v1 Service_ID 后,您可以通过参考来确定 v2 依赖项的相应的 Maven 工件。Maven ArtifactID 映射的软件包名称

4. 将 v2 依赖项元素添加到 POM 文件中

使用步骤 3 中确定的依赖元素更新 Maven POM 文件。

5. 在 Java 文件中,逐渐将 v1 类更改为 v2 类

在用 v2 类替换 v1 类时,请进行必要的更改以支持 v2 API,例如使用构建器而不是构造函数,以及使用流畅的 getter 和 setter。

6. 从 POM 中移除 v1 Maven 依赖关系,从文件中移除 v1 导入的依赖关系

将代码迁移到使用 v2 类后,请从文件中移除所有剩余的 v1 导入,并从构建文件中移除所有依赖项。

7. 重构代码以使用 v2 API 增强功能

代码成功编译并通过测试后,您可以利用 v2 增强功能,例如使用不同的 HTTP 客户端或分页器来简化代码。此为可选步骤。

迁移示例

在此示例中,我们迁移了一个使用 SDK for Java v1 并可以访问多个应用程序。 Amazon Web Services我们在步骤 5 中详细研究了以下 v1 方法。这是包含八个方法的类中的一个方法,应用程序中有 32 个类。

下面仅列出了从 Java 文件中导入的 v1 软件开发工具包。

import com.amazonaws.ClientConfiguration; import com.amazonaws.regions.Region; import com.amazonaws.regions.RegionUtils; import com.amazonaws.services.ec2.AmazonEC2Client; import com.amazonaws.services.ec2.model.AmazonEC2Exception; import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.DescribeInstancesRequest; import com.amazonaws.services.ec2.model.DescribeInstancesResult; import com.amazonaws.services.ec2.model.Instance; import com.amazonaws.services.ec2.model.InstanceStateName; import com.amazonaws.services.ec2.model.Reservation; import com.amazonaws.services.ec2.model.Tag; import com.amazonaws.services.ec2.model.TerminateInstancesRequest; ... private static List<Instance> getRunningInstances(AmazonEC2Client ec2, List<String> instanceIds) { List<Instance> runningInstances = new ArrayList<>(); try { DescribeInstancesRequest request = new DescribeInstancesRequest() .withInstanceIds(instanceIds); DescribeInstancesResult result; do { // DescribeInstancesResponse is a paginated response, so use tokens with multiple requests. result = ec2.describeInstances(request); request.setNextToken(result.getNextToken()); // Prepare request for next page. for (final Reservation r : result.getReservations()) { for (final Instance instance : r.getInstances()) { LOGGER.info("Examining instanceId: "+ instance.getInstanceId()); // if instance is in a running state, add it to runningInstances list. if (RUNNING_STATES.contains(instance.getState().getName())) { runningInstances.add(instance); } } } } while (result.getNextToken() != null); } catch (final AmazonEC2Exception exception) { // if instance isn't found, assume its terminated and continue. if (exception.getErrorCode().equals(NOT_FOUND_ERROR_CODE)) { LOGGER.info("Instance probably terminated; moving on."); } else { throw exception; } } return runningInstances; }

1. 添加 v2 Maven BOM

将适用于 Java SDK 2.x 的 Maven BOM 以及该部分中的任何其他依赖项一起添加到 POM 中dependencyManagement。如果您的 POM 文件中有 SDK 版本 1 的 BOM,请暂时将其保留。它将在以后的步骤中删除。

<dependencyManagement> <dependencies> <dependency> <groupId>org.example</groupId> <!--Existing dependency in POM. --> <artifactId>bom</artifactId> <version>1.3.4</version> <type>pom</type> <scope>import</scope> </dependency> ... <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-bom</artifactId> <!--Existing v1 BOM dependency. --> <version>1.11.1000</version> <type>pom</type> <scope>import</scope> </dependency> ... <dependency> <groupId>software.amazon.awssdk</groupId> <!--Add v2 BOM dependency. --> <artifactId>bom</artifactId> <version>2.24.3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

2. 在文件中搜索 v1 类的导入语句

在应用程序的代码中搜索唯一出现的。import com.amazonaws.services这可以帮助我们确定项目使用的 v1 依赖关系。如果您的应用程序有一个列出了 v1 依赖项的 Maven POM 文件,则可以改用此信息。

在这个例子中,我们使用 ripgrep(rg) 命令来搜索代码库。

从代码库的根目录执行以下ripgrep命令。ripgrep找到导入语句后,会将它们通过管道传送到cutsort、和uniq命令以隔离 Service_ID。

rg --no-filename 'import\s+com\.amazonaws\.services' | cut -d '.' -f 4 | sort | uniq

对于此应用程序,将以下 Service_ID 记录到控制台。

autoscaling cloudformation ec2 identitymanagement

这表明import语句中使用的以下每个软件包名称至少出现一次。我们的目的有四,各个类名无关紧要。我们只需要找到使用的服务 ID 即可。

com.amazonaws.services.autoscaling.* com.amazonaws.services.cloudformation.* com.amazonaws.services.ec2.* com.amazonaws.services.identitymanagement.*

3. 从 v1 的导入语句中确定 v2 Maven 的依赖关系

我们从步骤 2 中分离出来的 v1 的 service_ID(例如autoscalingcloudformation)在大多数情况下可以映射到相同的 v2 SERVICE_ID。由于 v2 Maven ArtifactID 在大多数情况下都与 SERVICE_ID 匹配,因此你拥有向 POM 文件添加依赖块所需的信息。

下表显示了我们如何确定 v2 依赖关系。

v1 SERVICE_ID 映射到...

包名

v2 SERVICE_ID 映射到...

包名

v2 Maven 依赖关系

ec2

com.amazonaws.services.ec2.*

ec2

software.amazon.awssdk.services.ec2.*

<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>ec2</artifactId> </dependency>

自动缩放

com.amazonaws.services.autoscaling.*

自动缩放

software.amazon.awssdk.services.autoscaling.*

<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>autoscaling</artifactId> </dependency>
cloudformation

com.amazonaws.services.cloudformation.*

cloudformation

software.amazon.awssdk.cloudformation.*

<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>cloudformation</artifactId> </dependency>
身份管理*

com.amazonaws.services.identitymanagement.*

我*

software.amazon.awssdk.iam.*

<dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>iam</artifactId> </dependency>

* to identitymanagement iam 映射是一个例外,其中 SERVICE_ID 因版本而异。如果 Maven 或 Gradle 无法解析 v2 依赖关系,请参阅了解例外情况。Maven ArtifactID 映射的软件包名称

4. 将 v2 依赖项元素添加到 POM 文件中

在步骤 3 中,我们确定了需要添加到 POM 文件中的四个依赖块。我们不需要添加版本,因为我们在步骤 1 中指定了 BOM。添加导入后,我们的 POM 文件具有以下依赖元素。

... <dependencies> ... <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>autoscaling</artifactId> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>iam</artifactId> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>cloudformation</artifactId> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>ec2</artifactId> </dependency> ... </dependencies> ...

5. 在 Java 文件中,逐渐将 v1 类更改为 v2 类

在我们正在迁移的方法中,我们看到

  • 来自 EC2 服务客户端com.amazonaws.services.ec2.AmazonEC2Client

  • 使用了几个 EC2 模型类。例如DescribeInstancesRequestDescribeInstancesResult

import com.amazonaws.ClientConfiguration; import com.amazonaws.regions.Region; import com.amazonaws.regions.RegionUtils; import com.amazonaws.services.ec2.AmazonEC2Client; import com.amazonaws.services.ec2.model.AmazonEC2Exception; import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.DescribeInstancesRequest; import com.amazonaws.services.ec2.model.DescribeInstancesResult; import com.amazonaws.services.ec2.model.Instance; import com.amazonaws.services.ec2.model.InstanceStateName; import com.amazonaws.services.ec2.model.Reservation; import com.amazonaws.services.ec2.model.Tag; import com.amazonaws.services.ec2.model.TerminateInstancesRequest; ... private static List<Instance> getRunningInstances(AmazonEC2Client ec2, List<String> instanceIds) List<Instance> runningInstances = new ArrayList<>(); try { DescribeInstancesRequest request = new DescribeInstancesRequest() .withInstanceIds(instanceIds); DescribeInstancesResult result; do { // DescribeInstancesResponse is a paginated response, so use tokens with multiple re result = ec2.describeInstances(request); request.setNextToken(result.getNextToken()); // Prepare request for next page. for (final Reservation r : result.getReservations()) { for (final Instance instance : r.getInstances()) { LOGGER.info("Examining instanceId: "+ instance.getInstanceId()); // if instance is in a running state, add it to runningInstances list. if (RUNNING_STATES.contains(instance.getState().getName())) { runningInstances.add(instance); } } } } while (result.getNextToken() != null); } catch (final AmazonEC2Exception exception) { // if instance isn't found, assume its terminated and continue. if (exception.getErrorCode().equals(NOT_FOUND_ERROR_CODE)) { LOGGER.info("Instance probably terminated; moving on."); } else { throw exception; } } return runningInstances; } ...

我们的目标是用 v2 导入替换所有 v1 导入。我们一次只能上一堂课。

a. 替换导入语句或类名

我们看到该describeRunningInstances方法的第一个参数是 v1 AmazonEC2Client 实例。请执行以下操作之一:

  • 将的导入替换为 com.amazonaws.services.ec2.AmazonEC2Clientsoftware.amazon.awssdk.services.ec2.Ec2Client,然后更改AmazonEC2ClientEc2Client

  • 将参数类型更改为Ec2Client,让 IDE 提示我们正确导入。由于客户端名称不同,我们的 IDE 会提示我们导入 v2 类,而AmazonEC2Client且。Ec2Client如果两个版本中的类名相同,则此方法不起作用。

b. 将 v1 模型类替换为 v2 等效项

在 v2 更改之后Ec2Client,如果我们使用 IDE,则会在以下语句中看到编译错误。

result = ec2.describeInstances(request);

编译错误源于使用 v1 的实例DescribeInstancesRequest作为 v2 Ec2Client describeInstances 方法的参数。要修复此问题,请使用以下替换语句或导入语句。

replace 替换为
import com.amazonaws.services.ec2.model.DescribeInstancesRequest
import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest

c. 将 v1 构造函数更改为 v2 构建器。

我们仍然看到编译错误,因为 v2 类上没有构造函数。要修复此问题,请进行以下更改。

更改
final DescribeInstancesRequest request = new DescribeInstancesRequest() .withInstanceIds(instanceIdsCopy);
final DescribeInstancesRequest request = DescribeInstancesRequest.builder() .instanceIds(instanceIdsCopy) .build();

d. 将 v1 *Result 响应对象替换为 v *Response 2 等效对象

v1 和 v2 之间的一致区别是,v2 中的所有响应对象都以而不是结*Response尾*Result将 v1 DescribeInstancesResult 导入替换为 v2 导入,。DescribeInstancesResponse

d. 更改 API

以下语句需要进行一些修改。

request.setNextToken(result.getNextToken());

在 v2 中,setter 方法不使用set或 with。prefix前缀为的 Getter 方法get也已在 Java 2.x 的 SDK 中消失

模型类(例如request实例)在 v2 中是不可变的,因此我们需要DescribeInstancesRequest使用构建器创建一个新的模型。

在 v2 中,该语句变为以下内容。

request = DescribeInstancesRequest.builder() .nextToken(result.nextToken()) .build();

d. 重复直到方法使用 v2 类进行编译

继续执行代码的其余部分。用 v2 导入替换 v1 导入并修复编译错误。如有必要,请参阅 v2 API 参考不同之处参考

在我们迁移这个单一方法之后,我们有了以下 v2 代码。

import com.amazonaws.ClientConfiguration; import com.amazonaws.regions.Region; import com.amazonaws.regions.RegionUtils; import com.amazonaws.services.ec2.AmazonEC2Client; import com.amazonaws.services.ec2.model.AmazonEC2Exception; import com.amazonaws.services.ec2.model.CreateTagsRequest; import com.amazonaws.services.ec2.model.InstanceStateName; import com.amazonaws.services.ec2.model.Tag; import com.amazonaws.services.ec2.model.TerminateInstancesRequest; import software.amazon.awssdk.services.ec2.Ec2Client; import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest; import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse; import software.amazon.awssdk.services.ec2.model.Ec2Exception; import software.amazon.awssdk.services.ec2.model.Instance; import software.amazon.awssdk.services.ec2.model.Reservation; ... private static List<Instance> getRunningInstances(Ec2Client ec2, List<String> instanceIds) { List<Instance> runningInstances = new ArrayList<>(); try { DescribeInstancesRequest request = DescribeInstancesRequest.builder() .instanceIds(instanceIds) .build(); DescribeInstancesResponse result; do { // DescribeInstancesResponse is a paginated response, so use tokens with multiple re result = ec2.describeInstances(request); request = DescribeInstancesRequest.builder() // Prepare request for next page. .nextToken(result.nextToken()) .build(); for (final Reservation r : result.reservations()) { for (final Instance instance : r.instances()) { // if instance is in a running state, add it to runningInstances list. if (RUNNING_STATES.contains(instance.state().nameAsString())) { runningInstances.add(instance); } } } } while (result.nextToken() != null); } catch (final Ec2Exception exception) { // if instance isn't found, assume its terminated and continue. if (exception.awsErrorDetails().errorCode().equals(NOT_FOUND_ERROR_CODE)) { LOGGER.info("Instance probably terminated; moving on."); } else { throw exception; } } return runningInstances; } ...

由于我们在使用八种方法迁移 Java 文件中的单个方法,因此在处理文件时会混合使用 v1 和 v2 导入。我们在执行这些步骤时添加了最后六个 import 语句。

在我们迁移所有代码之后,将不再有 v1 导入语句。

6. 从 POM 中移除 v1 Maven 依赖关系,从文件中移除 v1 导入的依赖关系

迁移文件中的所有 v1 代码后,我们有以下 v2 SDK 导入语句。

import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.regions.ServiceMetadata; import software.amazon.awssdk.services.ec2.Ec2Client; import software.amazon.awssdk.services.ec2.model.CreateTagsRequest; import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest; import software.amazon.awssdk.services.ec2.model.DescribeInstancesResponse; import software.amazon.awssdk.services.ec2.model.Ec2Exception; import software.amazon.awssdk.services.ec2.model.Instance; import software.amazon.awssdk.services.ec2.model.InstanceStateName; import software.amazon.awssdk.services.ec2.model.Reservation; import software.amazon.awssdk.services.ec2.model.Tag; import software.amazon.awssdk.services.ec2.model.TerminateInstancesRequest;

在我们迁移应用程序中的所有文件后,我们不再需要 POM 文件中的 v1 依赖项。从该dependencyManagement部分中删除 v1 BOM(如果使用)以及所有 v1 依赖项块。

7. 重构代码以使用 v2 API 增强功能

对于我们一直在迁移的片段,我们可以选择使用 v2 分页器,让 SDK 管理基于令牌的更多数据请求。

我们可以将整个子do句替换为以下内容。

DescribeInstancesIterable responses = ec2.describeInstancesPaginator(request); responses.reservations().stream() .forEach(reservation -> reservation.instances() .forEach(instance -> { if (RUNNING_STATES.contains(instance.state().nameAsString())) { runningInstances.put(instance.instanceId(), instance); } }));