本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
带示例的迁移 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
找到导入语句后,会将它们通过管道传送到cut
sort
、和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 服务名称(例如autoscaling
和cloudformation
)在大多数情况下可以映射到相同的 v2 服务名称。由于 v2 Maven ArtifactID 在大多数情况下都与服务名称匹配,因此您可以获得向 POM 文件添加依赖块所需的信息。
下表显示了我们如何确定 v2 依赖关系。
v1 服务名称映射到... 包名 |
v2 服务名称映射到... 包名 |
v2 Maven 依赖关系 |
---|---|---|
ec2
|
ec2
|
|
自动缩放
|
自动缩放
|
|
cloudformation
|
cloudformation
|
|
身份管理*
|
我*
|
|
* 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 模型类。例如
DescribeInstancesRequest
和DescribeInstancesResult
。
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.AmazonEC2Client
software.amazon.awssdk.services.ec2.Ec2Client
,然后更改AmazonEC2Client
为Ec2Client
。 -
将参数类型更改为
Ec2Client
,让 IDE 提示我们正确导入。由于客户端名称不同,我们的 IDE 会提示我们导入 v2 类,而AmazonEC2Client
且。Ec2Client
如果两个版本中的类名相同,则此方法不起作用。
b. 将 v1 模型类替换为 v2 等效项
在 v2 更改之后Ec2Client
,如果我们使用 IDE,则会在以下语句中看到编译错误。
result = ec2.describeInstances(request);
编译错误是由于使用 v1 的实例DescribeInstancesRequest
作为 v2 Ec2Client
describeInstances
方法的参数而导致的。要修复此问题,请使用以下替换语句或导入语句。
replace | 替换为 |
---|---|
|
|
c. 将 v1 构造函数更改为 v2 构建器。
我们仍然会看到编译错误,因为 v2 类上没有构造函数。要修复此问题,请进行以下更改。
更改 | 到 |
---|---|
|
|
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); } }));