带示例的迁移 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 导入,您将找到要添加到 Maven POM 文件中的 v2 依赖项。

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

找到所有唯一的 v1 导入语句后,您可以通过参考 Package 名称到依赖关系映射表来确定 v2 依赖项的相应的 Maven 工件。

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

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

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

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

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

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

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 for 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命令以隔离服务名。

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

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

autoscaling cloudformation ec2 identitymanagement

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

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

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

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

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

v1 服务名称映射到...

包名

v2 服务名称映射到...

包名

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>

* t identitymanagement o iam 映射是一个例外,即软件包名称中使用的服务名称因版本而异。

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 依赖项。从 “依赖管理” 部分(如果使用)中删除 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); } }));