

 适用于 Java 的 AWS SDK 1.x于2025年 end-of-support 12月31日达到。我们建议您迁移到 [AWS SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/home.html) 以继续获得新功能、可用性改进和安全更新。

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

# 适用于 Java 的 AWS SDK 代码示例
<a name="prog-services"></a>

本部分提供使用适用于 Java 的 AWS SDK v1 对 AWS 服务进行编程的教程和示例。

您可以在 [GitHub 上的代码示例库](https://github.com/awsdocs/aws-doc-sdk-examples) AWS 文档中找到这些示例及其他示例的源代码。

要向 AWS 文档团队提请考虑生成新的代码示例，请创建新的请求。该团队正在寻求生成涵盖更多应用场景和使用情形的代码示例，而不仅仅是涵盖个别 API 调用的简单代码片段。有关说明，请参阅 GitHub 上的代码示例存储库中的 [Contributing guidelines](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/CONTRIBUTING.md)。

## 适用于 Java 的 AWS SDK 2.x
<a name="aws-sdk-for-java-2-x"></a>

2018 年，AWS 发布了[AWS SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/home.html)。本指南包含有关使用最新 Java SDK 的说明以及示例代码。

**注意**  
如需可供 [ 开发人员使用的更多示例和其他资源，请参阅](welcome.md#additional-resources)其他文档和资源适用于 Java 的 AWS SDK！

**Topics**

# 使用适用于 Java 的 AWS SDK 的 CloudWatch 示例
<a name="examples-cloudwatch"></a>

此部分提供使用[适用于 Java 的 AWS SDK](https://aws.amazon.com/sdk-for-java/) 对 [CloudWatch](https://aws.amazon.com/cloudwatch/) 进行编程的示例。

Amazon CloudWatch 实时监控您的 Amazon Web Services (AWS) 资源以及在 AWS 上运行的应用程序。您可以使用 CloudWatch 收集和跟踪指标，这些指标是您可衡量的相关资源和应用程序的变量。CloudWatch 警报可根据您定义的规则发送通知或者对您所监控的资源自动进行更改。

有关 CloudWatch 的更多信息，请参阅 [Amazon CloudWatch 用户指南](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/)。

**注意**  
这些示例仅包含演示每种方法所需的代码。[完整的示例代码在 GitHub 上提供](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/java)。您可以在那里下载单个源文件，也可以将存储库复制到本地以获得所有示例，然后构建并运行这些示例。

**Topics**
+ [从 CloudWatch 获取指标](examples-cloudwatch-get-metrics.md)
+ [发布自定义指标数据](examples-cloudwatch-publish-custom-metrics.md)
+ [使用 CloudWatch 警报](examples-cloudwatch-create-alarms.md)
+ [在 CloudWatch 中使用警报操作](examples-cloudwatch-use-alarm-actions.md)
+ [将 事件发送到 CloudWatch](examples-cloudwatch-send-events.md)

# 从 CloudWatch 获取指标
<a name="examples-cloudwatch-get-metrics"></a>

## 列出指标
<a name="listing-metrics"></a>

要列出 CloudWatch 指标，请创建 [ListMetricsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/ListMetricsRequest.html) 并调用 AmazonCloudWatchClient 的 `listMetrics` 方法。您可以使用 `ListMetricsRequest` 通过命名空间、指标名称或维度筛选返回的指标。

**注意**  
AWS 服务发布的指标和维度列表可在《Amazon CloudWatch 用户指南》的 \$1https---docs-aws-amazon-com-AmazonCloudWatch-latest-monitoring-CW-Support-For-AWS-html\$1[Amazon CloudWatch 指标和维度参考] 中找到。

 **导入**。

```
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder;
import com.amazonaws.services.cloudwatch.model.ListMetricsRequest;
import com.amazonaws.services.cloudwatch.model.ListMetricsResult;
import com.amazonaws.services.cloudwatch.model.Metric;
```

 **代码** 

```
final AmazonCloudWatch cw =
    AmazonCloudWatchClientBuilder.defaultClient();

ListMetricsRequest request = new ListMetricsRequest()
        .withMetricName(name)
        .withNamespace(namespace);

boolean done = false;

while(!done) {
    ListMetricsResult response = cw.listMetrics(request);

    for(Metric metric : response.getMetrics()) {
        System.out.printf(
            "Retrieved metric %s", metric.getMetricName());
    }

    request.setNextToken(response.getNextToken());

    if(response.getNextToken() == null) {
        done = true;
    }
}
```

调用指标的 `getMetrics` 方法可在 [ListMetricsResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/ListMetricsResult.html) 中返回指标。结果可以*分页*。要检索下一批结果，请在原始请求对象中使用 `setNextToken` 对象的 `ListMetricsResult` 方法的返回值调用 `getNextToken`，并将已修改的请求对象传回对 `listMetrics` 的另一个调用。

## 更多信息
<a name="more-information"></a>
+  《Amazon CloudWatch API Reference》中的 [ListMetrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_ListMetrics.html)。

# 发布自定义指标数据
<a name="examples-cloudwatch-publish-custom-metrics"></a>

许多 AWS 服务以“`AWS`”开头的命名空间发布[它们自己的指标](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-namespaces.html)。您也可以使用自己的命名空间发布自定义指标数据（不以“`AWS`”开头即可）。

## 发布自定义指标数据
<a name="publish-custom-metric-data"></a>

要发布自己的指标数据，请使用 [PutMetricDataRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/PutMetricDataRequest.html) 调用 AmazonCloudWatchClient 的 `putMetricData` 方法。`PutMetricDataRequest` 必须包括数据要使用的自定义命名空间，还必须在 [MetricDatum](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/MetricDatum.html) 对象中包含有关该数据点本身的信息。

**注意**  
您无法指定以“`AWS`”开头的命名空间。以“`AWS`”开头的命名空间保留供 Amazon Web Services 产品使用。

 **导入**。

```
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder;
import com.amazonaws.services.cloudwatch.model.Dimension;
import com.amazonaws.services.cloudwatch.model.MetricDatum;
import com.amazonaws.services.cloudwatch.model.PutMetricDataRequest;
import com.amazonaws.services.cloudwatch.model.PutMetricDataResult;
import com.amazonaws.services.cloudwatch.model.StandardUnit;
```

 **代码** 

```
final AmazonCloudWatch cw =
    AmazonCloudWatchClientBuilder.defaultClient();

Dimension dimension = new Dimension()
    .withName("UNIQUE_PAGES")
    .withValue("URLS");

MetricDatum datum = new MetricDatum()
    .withMetricName("PAGES_VISITED")
    .withUnit(StandardUnit.None)
    .withValue(data_point)
    .withDimensions(dimension);

PutMetricDataRequest request = new PutMetricDataRequest()
    .withNamespace("SITE/TRAFFIC")
    .withMetricData(datum);

PutMetricDataResult response = cw.putMetricData(request);
```

## 更多信息
<a name="more-information"></a>
+  《Amazon CloudWatch 用户指南》中的[使用 Amazon CloudWatch 指标](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/working_with_metrics.html)。
+  《Amazon CloudWatch 用户指南》中的[AWS 命名空间](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-namespaces.html)。
+  《Amazon CloudWatch API Reference》中的 [PutMetricData](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_PutMetricData.html)。

# 使用 CloudWatch 警报
<a name="examples-cloudwatch-create-alarms"></a>

## 创建警报
<a name="create-an-alarm"></a>

要根据 CloudWatch 指标创建警报，请使用已填充警报条件的 [PutMetricAlarmRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/PutMetricAlarmRequest.html) 调用 AmazonCloudWatchClient 的 `putMetricAlarm` 方法。

 **导入**。

```
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder;
import com.amazonaws.services.cloudwatch.model.ComparisonOperator;
import com.amazonaws.services.cloudwatch.model.Dimension;
import com.amazonaws.services.cloudwatch.model.PutMetricAlarmRequest;
import com.amazonaws.services.cloudwatch.model.PutMetricAlarmResult;
import com.amazonaws.services.cloudwatch.model.StandardUnit;
import com.amazonaws.services.cloudwatch.model.Statistic;
```

 **代码** 

```
final AmazonCloudWatch cw =
    AmazonCloudWatchClientBuilder.defaultClient();

Dimension dimension = new Dimension()
    .withName("InstanceId")
    .withValue(instanceId);

PutMetricAlarmRequest request = new PutMetricAlarmRequest()
    .withAlarmName(alarmName)
    .withComparisonOperator(
        ComparisonOperator.GreaterThanThreshold)
    .withEvaluationPeriods(1)
    .withMetricName("CPUUtilization")
    .withNamespace("{AWS}/EC2")
    .withPeriod(60)
    .withStatistic(Statistic.Average)
    .withThreshold(70.0)
    .withActionsEnabled(false)
    .withAlarmDescription(
        "Alarm when server CPU utilization exceeds 70%")
    .withUnit(StandardUnit.Seconds)
    .withDimensions(dimension);

PutMetricAlarmResult response = cw.putMetricAlarm(request);
```

## 列出警报
<a name="list-alarms"></a>

要列出您已创建的 CloudWatch 警报，请使用您可用来设置结果选项的 [DescribeAlarmsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/DescribeAlarmsRequest.html) 调用 AmazonCloudWatchClient 的 `describeAlarms` 方法。

 **导入**。

```
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder;
import com.amazonaws.services.cloudwatch.model.DescribeAlarmsRequest;
import com.amazonaws.services.cloudwatch.model.DescribeAlarmsResult;
import com.amazonaws.services.cloudwatch.model.MetricAlarm;
```

 **代码** 

```
final AmazonCloudWatch cw =
    AmazonCloudWatchClientBuilder.defaultClient();

boolean done = false;
DescribeAlarmsRequest request = new DescribeAlarmsRequest();

while(!done) {

    DescribeAlarmsResult response = cw.describeAlarms(request);

    for(MetricAlarm alarm : response.getMetricAlarms()) {
        System.out.printf("Retrieved alarm %s", alarm.getAlarmName());
    }

    request.setNextToken(response.getNextToken());

    if(response.getNextToken() == null) {
        done = true;
    }
}
```

警报列表可以通过在 `describeAlarms` 返回的 [DescribeAlarmsResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/DescribeAlarmsResult.html) 中调用 `getMetricAlarms` 获得。

结果可以*分页*。要检索下一批结果，请在原始请求对象中使用 `setNextToken` 对象的 `DescribeAlarmsResult` 方法的返回值调用 `getNextToken`，并将已修改的请求对象传回对 `describeAlarms` 的另一个调用。

**注意**  
您还可以使用 AmazonCloudWatchClient 的 `describeAlarmsForMetric` 方法检索特定指标的警报。它的使用类似于 `describeAlarms`。

## 删除警报
<a name="delete-alarms"></a>

要删除 CloudWatch 警报，请使用 [DeleteAlarmsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/DeleteAlarmsRequest.html)（包含您要删除的一个或更多警报名称）调用 AmazonCloudWatchClient 的 `deleteAlarms` 方法。

 **导入**。

```
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder;
import com.amazonaws.services.cloudwatch.model.DeleteAlarmsRequest;
import com.amazonaws.services.cloudwatch.model.DeleteAlarmsResult;
```

 **代码** 

```
final AmazonCloudWatch cw =
    AmazonCloudWatchClientBuilder.defaultClient();

DeleteAlarmsRequest request = new DeleteAlarmsRequest()
    .withAlarmNames(alarm_name);

DeleteAlarmsResult response = cw.deleteAlarms(request);
```

## 更多信息
<a name="more-information"></a>
+  《Amazon CloudWatch 用户指南》中的[创建 Amazon CloudWatch 警报](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html)
+  《Amazon CloudWatch API Reference》中的 [PutMetricAlarm](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_PutMetricAlarm.html)
+  《Amazon CloudWatch API Reference》中的 [DescribeAlarms](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_DescribeAlarms.html)
+  《Amazon CloudWatch API Reference》中的 [DeleteAlarms](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_DeleteAlarms.html)

# 在 CloudWatch 中使用警报操作
<a name="examples-cloudwatch-use-alarm-actions"></a>

利用 CloudWatch 警报操作，您可创建执行自动停止、终止、重启或恢复 Amazon EC2 实例等操作的警报。

**注意**  
通过在[创建警报](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/PutMetricAlarmRequest.html)时使用 `setAlarmActions`PutMetricAlarmRequest[ 的 ](examples-cloudwatch-create-alarms.md) 方法，可以将警报操作添加到警报。

## 启用警报操作
<a name="enable-alarm-actions"></a>

要启用 CloudWatch 警报的警报操作，请使用 [EnableAlarmActionsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/EnableAlarmActionsRequest.html)（包含一个或多个您要启用的警报的名称）调用 AmazonCloudWatchClient 的 `enableAlarmActions`。

 **导入**。

```
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder;
import com.amazonaws.services.cloudwatch.model.EnableAlarmActionsRequest;
import com.amazonaws.services.cloudwatch.model.EnableAlarmActionsResult;
```

 **代码** 

```
final AmazonCloudWatch cw =
    AmazonCloudWatchClientBuilder.defaultClient();

EnableAlarmActionsRequest request = new EnableAlarmActionsRequest()
    .withAlarmNames(alarm);

EnableAlarmActionsResult response = cw.enableAlarmActions(request);
```

## 禁用警报操作
<a name="disable-alarm-actions"></a>

要禁用 CloudWatch 警报的警报操作，请使用 [DisableAlarmActionsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatch/model/DisableAlarmActionsRequest.html)（包含一个或多个您要禁用其操作的警报的名称）调用 AmazonCloudWatchClient 的 `disableAlarmActions`。

 **导入**。

```
import com.amazonaws.services.cloudwatch.AmazonCloudWatch;
import com.amazonaws.services.cloudwatch.AmazonCloudWatchClientBuilder;
import com.amazonaws.services.cloudwatch.model.DisableAlarmActionsRequest;
import com.amazonaws.services.cloudwatch.model.DisableAlarmActionsResult;
```

 **代码** 

```
final AmazonCloudWatch cw =
    AmazonCloudWatchClientBuilder.defaultClient();

DisableAlarmActionsRequest request = new DisableAlarmActionsRequest()
    .withAlarmNames(alarmName);

DisableAlarmActionsResult response = cw.disableAlarmActions(request);
```

## 更多信息
<a name="more-information"></a>
+  《Amazon CloudWatch 指南》中的[创建警报以停止、终止、重启或恢复实例](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/UsingAlarmActions.html)
+  《Amazon CloudWatch API Reference》中的 [PutMetricAlarm](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_PutMetricAlarm.html)
+  《Amazon CloudWatch API Reference》中的 [EnableAlarmActions](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_EnableAlarmActions.html)
+  《Amazon CloudWatch API Reference》中的 [DisableAlarmActions](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_DisableAlarmActions.html)

# 将 事件发送到 CloudWatch
<a name="examples-cloudwatch-send-events"></a>

 CloudWatch Events 提供几乎实时的系统事件流，这些事件描述 AWS 资源中对 Amazon EC2 实例、Lambda 函数、Kinesis 流、Amazon ECS 任务、 Step Functions 状态机、Amazon SNS 主题、Amazon SQS 队列或内置目标的更改。通过使用简单的规则，您可以匹配事件并将事件路由到一个或多个目标函数或流。

## 添加事件
<a name="add-events"></a>

要添加自定义 CloudWatch 事件，请使用包含一个或多个 [PutEventsRequestEntry](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatchevents/model/PutEventsRequestEntry.html) 对象（提供每个事件的详细信息）的 [PutEventsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatchevents/model/PutEventsRequest.html) 对象调用 AmazonCloudWatchEventsClient 的 `putEvents` 方法。您可以为条目指定多个参数，例如事件的来源和类型、与事件相关联的资源等等。

**注意**  
对于每个 `putEvents` 调用，您最多可以指定 10 个事件。

 **导入**。

```
import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEventsClientBuilder;
import com.amazonaws.services.cloudwatchevents.model.PutEventsRequest;
import com.amazonaws.services.cloudwatchevents.model.PutEventsRequestEntry;
import com.amazonaws.services.cloudwatchevents.model.PutEventsResult;
```

 **代码** 

```
final AmazonCloudWatchEvents cwe =
    AmazonCloudWatchEventsClientBuilder.defaultClient();

final String EVENT_DETAILS =
    "{ \"key1\": \"value1\", \"key2\": \"value2\" }";

PutEventsRequestEntry request_entry = new PutEventsRequestEntry()
    .withDetail(EVENT_DETAILS)
    .withDetailType("sampleSubmitted")
    .withResources(resource_arn)
    .withSource("aws-sdk-java-cloudwatch-example");

PutEventsRequest request = new PutEventsRequest()
    .withEntries(request_entry);

PutEventsResult response = cwe.putEvents(request);
```

## 添加规则
<a name="add-rules"></a>

要创建或更新规则，请使用包含规则名称和可选参数的 [PutRuleRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatchevents/model/PutRuleRequest.html) 调用 AmazonCloudWatchEventsClient 的 `putRule` 方法，可选参数如[事件模式](https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/CloudWatchEventsandEventPatterns.html)、与规则相关联的 IAM 角色以及描述规则运行频率的[计划表达式](https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html)。

 **导入**。

```
import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEventsClientBuilder;
import com.amazonaws.services.cloudwatchevents.model.PutRuleRequest;
import com.amazonaws.services.cloudwatchevents.model.PutRuleResult;
import com.amazonaws.services.cloudwatchevents.model.RuleState;
```

 **代码** 

```
final AmazonCloudWatchEvents cwe =
    AmazonCloudWatchEventsClientBuilder.defaultClient();

PutRuleRequest request = new PutRuleRequest()
    .withName(rule_name)
    .withRoleArn(role_arn)
    .withScheduleExpression("rate(5 minutes)")
    .withState(RuleState.ENABLED);

PutRuleResult response = cwe.putRule(request);
```

## 添加目标
<a name="add-targets"></a>

目标是触发规则时调用的资源。示例目标包括 Amazon EC2 实例、Lambda 函数、Kinesis 流、Amazon ECS 任务、Step Functions 状态机和内置目标。

要向规则添加目标，请使用 [PutTargetsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/cloudwatchevents/model/PutTargetsRequest.html)（包含要更新的规则和要添加到规则的目标列表）来调用 AmazonCloudWatchEventsClient 的 `putTargets` 方法。

 **导入**。

```
import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEventsClientBuilder;
import com.amazonaws.services.cloudwatchevents.model.PutTargetsRequest;
import com.amazonaws.services.cloudwatchevents.model.PutTargetsResult;
import com.amazonaws.services.cloudwatchevents.model.Target;
```

 **代码** 

```
final AmazonCloudWatchEvents cwe =
    AmazonCloudWatchEventsClientBuilder.defaultClient();

Target target = new Target()
    .withArn(function_arn)
    .withId(target_id);

PutTargetsRequest request = new PutTargetsRequest()
    .withTargets(target)
    .withRule(rule_name);

PutTargetsResult response = cwe.putTargets(request);
```

## 更多信息
<a name="more-information"></a>
+  《Amazon CloudWatch Events User Guide》中的 [Adding Events with PutEvents](https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/AddEventsPutEvents.html)
+  《Amazon CloudWatch Events User Guide》中的 [Schedule Expressions for Rules](https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html)
+  《Amazon CloudWatch Events User Guide》中的 [Event Types for CloudWatch Events](https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/EventTypes.html)
+  《Amazon CloudWatch Events User Guide》中的 [Events and Event Patterns](https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/CloudWatchEventsandEventPatterns.html)
+  《Amazon CloudWatch Events API Reference》中的 [PutEvents](https://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_PutEvents.html)
+  《Amazon CloudWatch Events API Reference》中的 [PutTargets](https://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_PutTargets.html)
+  《Amazon CloudWatch Events API Reference》中的 [PutRule](https://docs.aws.amazon.com/AmazonCloudWatchEvents/latest/APIReference/API_PutRule.html)

# 使用适用于 Java 的 AWS SDK 的 DynamoDB 示例
<a name="examples-dynamodb"></a>

此部分提供使用[适用于 Java 的 AWS SDK](https://aws.amazon.com/sdk-for-java/) 对 [DynamoDB](https://aws.amazon.com/dynamodb/) 进行编程的示例。

**注意**  
这些示例仅包含演示每种方法所需的代码。[完整的示例代码在 GitHub 上提供](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/java)。您可以在那里下载单个源文件，也可以将存储库复制到本地以获得所有示例，然后构建并运行这些示例。

**Topics**
+ [使用基于 AWS 账户的端点](#account-based-endpoint-routing)
+ [处理 DynamoDB 中的表](examples-dynamodb-tables.md)
+ [处理 DynamoDB 中的项目](examples-dynamodb-items.md)

## 使用基于 AWS 账户的端点
<a name="account-based-endpoint-routing"></a>

DynamoDB 提供[基于 AWS 账户的端点](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.SDKOverview.html#Programming.SDKs.endpoints)，通过使用您的 AWS 账户 ID 来简化请求路由，从而提升性能。

要使用此功能，您需要使用适用于 Java 的 AWS SDK 版本 1 的 1.12.771 或更高版本。[Maven Central 存储库](https://central.sonatype.com/artifact/com.amazonaws/aws-java-sdk-bom)中列出了 SDK 的最新版本。在受支持的 SDK 版本处于活动状态后，它会自动使用新的端点。

如果要选择退出基于账户的路由，您可以选择四个选项：
+ 配置 DynamoDB 服务客户端，将 `AccountIdEndpointMode` 设置为 `DISABLED`。
+ 设置环境变量。
+ 设置 JVM 系统属性。
+ 更新共享的 AWS 配置文件设置。

以下代码片段演示了如何通过配置 DynamoDB 服务客户端来禁用基于账户的路由：

```
ClientConfiguration config = new ClientConfiguration()
    .withAccountIdEndpointMode(AccountIdEndpointMode.DISABLED);
AWSCredentialsProvider credentialsProvider = new EnvironmentVariableCredentialsProvider();

AmazonDynamoDB dynamodb = AmazonDynamoDBClientBuilder.standard()
    .withClientConfiguration(config)
    .withCredentials(credentialsProvider)
    .withRegion(Regions.US_WEST_2)
    .build();
```

《AWS SDK 和工具参考指南》提供了有关最后[三个配置选项](https://docs.aws.amazon.com/sdkref/latest/guide/feature-account-endpoints.html)的更多信息。

# 处理 DynamoDB 中的表
<a name="examples-dynamodb-tables"></a>

表是 DynamoDB 数据库中所有项目的容器。您必须先创建表，然后才能在 DynamoDB 中添加或删除数据。

对于每个表，您必须定义：
+ 表*名称*，它对于您的账户和所在区域是唯一的。
+ 一个*主键*，每个值对于它都必须是唯一的；表中的任意两个项目不能具有相同的主键值。

  主键可以是*简单*主键（包含单个分区 (HASH) 键）或*复合*主键（包含一个分区和一个排序 (RANGE) 键）。

  每个键值均有一个由 *ScalarAttributeType* 类枚举的关联的[数据类型](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/ScalarAttributeType.html)。键值可以是二进制 (B)、数字 (N) 或字符串 (S)。有关更多信息，请参阅《Amazon DynamoDB 开发人员指南》中的[命名规则和数据类型](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html)。
+  *预置吞吐量*值，这些值定义为表保留的读取/写入容量单位数。
**注意**  
 [Amazon DynamoDB 定价](https://aws.amazon.com/dynamodb/pricing/)基于您为表设置的预置吞吐量值，因此您应只为表保留可能需要的容量。

表的预置吞吐量可随时修改，以便您能够在需要更改时调整容量。

## 创建表
<a name="dynamodb-create-table"></a>

使用 [DynamoDB 客户端](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/AmazonDynamoDB.html)的 `createTable` 方法可创建新的 DynamoDB 表。您需要构造表属性和表架构，二者用于标识表的主键。您还必须提供初始预置吞吐量值和表名。仅在创建 DynamoDB 表时定义键表属性。

**注意**  
如果使用您所选名称的表已存在，则将引发 [AmazonServiceException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/AmazonServiceException.html)。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.CreateTableResult;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
```

### 创建具有简单主键的表
<a name="dynamodb-create-table-simple"></a>

此代码使用简单主键 (“Name”) 创建表。

 **代码** 

```
CreateTableRequest request = new CreateTableRequest()
    .withAttributeDefinitions(new AttributeDefinition(
             "Name", ScalarAttributeType.S))
    .withKeySchema(new KeySchemaElement("Name", KeyType.HASH))
    .withProvisionedThroughput(new ProvisionedThroughput(
             new Long(10), new Long(10)))
    .withTableName(table_name);

final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();

try {
    CreateTableResult result = ddb.createTable(request);
    System.out.println(result.getTableDescription().getTableName());
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/dynamodb/src/main/java/aws/example/dynamodb/CreateTable.java)。

### 创建具有复合主键的表
<a name="dynamodb-create-table-composite"></a>

添加另一个 [AttributeDefinition](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/AttributeDefinition.html) 和 [KeySchemaElement](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/KeySchemaElement.html) 到 [CreateTableRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/CreateTableRequest.html)。

 **代码** 

```
CreateTableRequest request = new CreateTableRequest()
    .withAttributeDefinitions(
          new AttributeDefinition("Language", ScalarAttributeType.S),
          new AttributeDefinition("Greeting", ScalarAttributeType.S))
    .withKeySchema(
          new KeySchemaElement("Language", KeyType.HASH),
          new KeySchemaElement("Greeting", KeyType.RANGE))
    .withProvisionedThroughput(
          new ProvisionedThroughput(new Long(10), new Long(10)))
    .withTableName(table_name);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/dynamodb/src/main/java/aws/example/dynamodb/CreateTableCompositeKey.java)。

## 列出表
<a name="dynamodb-list-tables"></a>

您可以通过调用 [DynamoDB 客户端](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/AmazonDynamoDB.html)的 `listTables` 方法列出特定区域中的表。

**注意**  
如果您的账户和区域没有该已命名的表，则将引发 [ResourceNotFoundException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/ResourceNotFoundException.html) 异常。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.ListTablesRequest;
import com.amazonaws.services.dynamodbv2.model.ListTablesResult;
```

 **代码** 

```
final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();

ListTablesRequest request;

boolean more_tables = true;
String last_name = null;

while(more_tables) {
    try {
        if (last_name == null) {
        	request = new ListTablesRequest().withLimit(10);
        }
        else {
        	request = new ListTablesRequest()
        			.withLimit(10)
        			.withExclusiveStartTableName(last_name);
        }

        ListTablesResult table_list = ddb.listTables(request);
        List<String> table_names = table_list.getTableNames();

        if (table_names.size() > 0) {
            for (String cur_name : table_names) {
                System.out.format("* %s\n", cur_name);
            }
        } else {
            System.out.println("No tables found!");
            System.exit(0);
        }

        last_name = table_list.getLastEvaluatedTableName();
        if (last_name == null) {
            more_tables = false;
        }
```

默认情况下，每次调用将返回最多 100 个表 – 对返回的 [ListTablesResult](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/model/ListTablesResult.html) 对象使用 `getLastEvaluatedTableName` 可获得评估的上一个表。可使用此值在上一列出的最后一个返回值后开始列出。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/dynamodb/src/main/java/aws/example/dynamodb/ListTables.java)。

## 描述表（获取相关信息）
<a name="dynamodb-describe-table"></a>

调用 [DynamoDB 客户端](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/AmazonDynamoDB.html)的 `describeTable` 方法。

**注意**  
如果您的账户和区域没有该已命名的表，则将引发 [ResourceNotFoundException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/ResourceNotFoundException.html) 异常。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughputDescription;
import com.amazonaws.services.dynamodbv2.model.TableDescription;
```

 **代码** 

```
final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();

try {
    TableDescription table_info =
       ddb.describeTable(table_name).getTable();

    if (table_info != null) {
        System.out.format("Table name  : %s\n",
              table_info.getTableName());
        System.out.format("Table ARN   : %s\n",
              table_info.getTableArn());
        System.out.format("Status      : %s\n",
              table_info.getTableStatus());
        System.out.format("Item count  : %d\n",
              table_info.getItemCount().longValue());
        System.out.format("Size (bytes): %d\n",
              table_info.getTableSizeBytes().longValue());

        ProvisionedThroughputDescription throughput_info =
           table_info.getProvisionedThroughput();
        System.out.println("Throughput");
        System.out.format("  Read Capacity : %d\n",
              throughput_info.getReadCapacityUnits().longValue());
        System.out.format("  Write Capacity: %d\n",
              throughput_info.getWriteCapacityUnits().longValue());

        List<AttributeDefinition> attributes =
           table_info.getAttributeDefinitions();
        System.out.println("Attributes");
        for (AttributeDefinition a : attributes) {
            System.out.format("  %s (%s)\n",
                  a.getAttributeName(), a.getAttributeType());
        }
    }
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/dynamodb/src/main/java/aws/example/dynamodb/DescribeTable.java)。

## 修改（更新）表
<a name="dynamodb-update-table"></a>

您可以通过调用 [DynamoDB 客户端](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/AmazonDynamoDB.html)的 `updateTable` 方法随时修改表的预置吞吐量值。

**注意**  
如果您的账户和区域没有该已命名的表，则将引发 [ResourceNotFoundException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/ResourceNotFoundException.html) 异常。

 **导入**。

```
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.AmazonServiceException;
```

 **代码** 

```
ProvisionedThroughput table_throughput = new ProvisionedThroughput(
      read_capacity, write_capacity);

final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();

try {
    ddb.updateTable(table_name, table_throughput);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/dynamodb/src/main/java/aws/example/dynamodb/UpdateTable.java)。

## 删除表
<a name="dynamodb-delete-table"></a>

调用 [DynamoDB 客户端](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/AmazonDynamoDB.html)的 `deleteTable` 方法，并向其传递表名称。

**注意**  
如果您的账户和区域没有该已命名的表，则将引发 [ResourceNotFoundException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/ResourceNotFoundException.html) 异常。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
```

 **代码** 

```
final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();

try {
    ddb.deleteTable(table_name);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/dynamodb/src/main/java/aws/example/dynamodb/DeleteTable.java)。

## 更多信息
<a name="more-info"></a>
+  《Amazon DynamoDB 开发人员指南》中的[表处理准则](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html)
+  《Amazon DynamoDB 开发人员指南》中的[处理 DynamoDB 中的表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithTables.html)

# 处理 DynamoDB 中的项目
<a name="examples-dynamodb-items"></a>

在 DynamoDB 中，项目是*属性*的集合，每个项目都包括一个*名称*和一个*值*。属性值可以为标量、集或文档类型。有关更多信息，请参阅《Amazon DynamoDB 开发人员指南》中的[命名规则和数据类型](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html)。

## 检索 (获取) 表中的项目
<a name="dynamodb-get-item"></a>

调用 AmazonDynamoDB 的 `getItem` 方法，并向其传递 [GetItemRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/GetItemRequest.html) 对象，包含您所需项目的表名称和主键值。它返回 [GetItemResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/GetItemResult.html) 对象。

可以使用所返回 `GetItemResult` 对象的 `getItem()` 方法，检索与项目关联的[映射](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html)（键（字符串） 和值 ([AttributeValue](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/AttributeValue.html)) 对）。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
import java.util.HashMap;
import java.util.Map;
```

 **代码** 

```
HashMap<String,AttributeValue> key_to_get =
    new HashMap<String,AttributeValue>();

key_to_get.put("DATABASE_NAME", new AttributeValue(name));

GetItemRequest request = null;
if (projection_expression != null) {
    request = new GetItemRequest()
        .withKey(key_to_get)
        .withTableName(table_name)
        .withProjectionExpression(projection_expression);
} else {
    request = new GetItemRequest()
        .withKey(key_to_get)
        .withTableName(table_name);
}

final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();

try {
    Map<String,AttributeValue> returned_item =
       ddb.getItem(request).getItem();
    if (returned_item != null) {
        Set<String> keys = returned_item.keySet();
        for (String key : keys) {
            System.out.format("%s: %s\n",
                    key, returned_item.get(key).toString());
        }
    } else {
        System.out.format("No item found with the key %s!\n", name);
    }
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/dynamodb/src/main/java/aws/example/dynamodb/GetItem.java)。

## 向表添加新项目
<a name="dynamodb-add-item"></a>

创建表示项目属性的键值对的[映射](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html)。其中必须包括表的主键字段的值。如果主键标识的项目已存在，那么其字段将通过该请求*更新*。

**注意**  
如果您的账户和区域没有该已命名的表，则将引发 [ResourceNotFoundException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/ResourceNotFoundException.html) 异常。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.ResourceNotFoundException;
import java.util.ArrayList;
```

 **代码** 

```
HashMap<String,AttributeValue> item_values =
    new HashMap<String,AttributeValue>();

item_values.put("Name", new AttributeValue(name));

for (String[] field : extra_fields) {
    item_values.put(field[0], new AttributeValue(field[1]));
}

final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();

try {
    ddb.putItem(table_name, item_values);
} catch (ResourceNotFoundException e) {
    System.err.format("Error: The table \"%s\" can't be found.\n", table_name);
    System.err.println("Be sure that it exists and that you've typed its name correctly!");
    System.exit(1);
} catch (AmazonServiceException e) {
    System.err.println(e.getMessage());
    System.exit(1);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/dynamodb/src/main/java/aws/example/dynamodb/PutItem.java)。

## 更新表中现有项目
<a name="dynamodb-update-item"></a>

可以使用 AmazonDynamoDB 的 `updateItem` 方法，通过提供要更新的表名称、主键值和字段映射，更新表中已有项目的属性。

**注意**  
如果您的账户和区域没有该已命名的表，或者不存在传入的主键标识的项目，会导致 [ResourceNotFoundException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/model/ResourceNotFoundException.html) 异常。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.model.AttributeAction;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.AttributeValueUpdate;
import com.amazonaws.services.dynamodbv2.model.ResourceNotFoundException;
import java.util.ArrayList;
```

 **代码** 

```
HashMap<String,AttributeValue> item_key =
   new HashMap<String,AttributeValue>();

item_key.put("Name", new AttributeValue(name));

HashMap<String,AttributeValueUpdate> updated_values =
    new HashMap<String,AttributeValueUpdate>();

for (String[] field : extra_fields) {
    updated_values.put(field[0], new AttributeValueUpdate(
                new AttributeValue(field[1]), AttributeAction.PUT));
}

final AmazonDynamoDB ddb = AmazonDynamoDBClientBuilder.defaultClient();

try {
    ddb.updateItem(table_name, item_key, updated_values);
} catch (ResourceNotFoundException e) {
    System.err.println(e.getMessage());
    System.exit(1);
} catch (AmazonServiceException e) {
    System.err.println(e.getMessage());
    System.exit(1);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/dynamodb/src/main/java/aws/example/dynamodb/UpdateItem.java)。

## 使用 DynamoDBMapper 类
<a name="use-the-dynamodbmapper-class"></a>

[适用于 Java 的 AWS SDK](https://aws.amazon.com/sdk-for-java/) 提供了 [DynamoDBMapper](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html) 类，使您能够将客户端类映射到 Amazon DynamoDB 表。要使用 [DynamoDBMapper](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html) 类，您可以使用注释定义 DynamoDB 表中的项目与代码中相应的对象实例之间的关系（如下面的代码示例所示）。利用 [DynamoDBMapper](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html) 类，您能够访问自己的表，执行各种创建、读取、更新和删除 (CRUD) 操作，并执行查询。

**注意**  
[DynamoDBMapper](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html) 类不允许创建、更新或删除表。

 **导入**。

```
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.model.AmazonDynamoDBException;
```

 **代码** 

以下 Java 代码示例演示如何使用 [DynamoDBMapper](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html) 类向 *Music* 表添加内容。将内容添加到表中后，请注意使用 *Partition (分区)* 和 *Sort (排序)* 键加载项目。然后 *Awards (奖项)* 项目会更新。有关创建 *Music* 表的信息，请参阅《Amazon DynamoDB 开发人员指南》中的[创建表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/getting-started-step-1.html)。

```
       AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
       MusicItems items = new MusicItems();

       try{
           // Add new content to the Music table
           items.setArtist(artist);
           items.setSongTitle(songTitle);
           items.setAlbumTitle(albumTitle);
           items.setAwards(Integer.parseInt(awards)); //convert to an int

           // Save the item
           DynamoDBMapper mapper = new DynamoDBMapper(client);
           mapper.save(items);

           // Load an item based on the Partition Key and Sort Key
           // Both values need to be passed to the mapper.load method
           String artistName = artist;
           String songQueryTitle = songTitle;

           // Retrieve the item
           MusicItems itemRetrieved = mapper.load(MusicItems.class, artistName, songQueryTitle);
           System.out.println("Item retrieved:");
           System.out.println(itemRetrieved);

           // Modify the Award value
           itemRetrieved.setAwards(2);
           mapper.save(itemRetrieved);
           System.out.println("Item updated:");
           System.out.println(itemRetrieved);

           System.out.print("Done");
       } catch (AmazonDynamoDBException e) {
           e.getStackTrace();
       }
   }

   @DynamoDBTable(tableName="Music")
   public static class MusicItems {

       //Set up Data Members that correspond to columns in the Music table
       private String artist;
       private String songTitle;
       private String albumTitle;
       private int awards;

       @DynamoDBHashKey(attributeName="Artist")
       public String getArtist() {
           return this.artist;
       }

       public void setArtist(String artist) {
           this.artist = artist;
       }

       @DynamoDBRangeKey(attributeName="SongTitle")
       public String getSongTitle() {
           return this.songTitle;
       }

       public void setSongTitle(String title) {
           this.songTitle = title;
       }

       @DynamoDBAttribute(attributeName="AlbumTitle")
       public String getAlbumTitle() {
           return this.albumTitle;
       }

       public void setAlbumTitle(String title) {
           this.albumTitle = title;
       }

       @DynamoDBAttribute(attributeName="Awards")
       public int getAwards() {
           return this.awards;
       }

       public void setAwards(int awards) {
           this.awards = awards;
       }
   }
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/dynamodb/src/main/java/aws/example/dynamodb/UseDynamoMapping.java)。

## 更多信息
<a name="more-info"></a>
+  《Amazon DynamoDB 开发人员指南》中的[项目处理准则](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForItems.html)
+  《Amazon DynamoDB 开发人员指南》中的[处理 DynamoDB 中的项目](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html)

# Amazon EC2使用 的 示例适用于 Java 的 AWS SDK
<a name="prog-services-ec2"></a>

本部分提供使用适用于 Java 的 AWS SDK 对 [Amazon EC2](https://aws.amazon.com/ec2/) 进行编程的示例。

**Topics**
+ [教程：启动 EC2 实例](how-to-ec2.md)
+ [使用 IAM 角色授予对 Amazon EC2 上的 AWS 资源的访问权](java-dg-roles.md)
+ [教程：Amazon EC2 竞价型实例](tutorial-spot-instances-java.md)
+ [教程：高级 Amazon EC2 竞价型实例请求管理](tutorial-spot-adv-java.md)
+ [管理 Amazon EC2实例](examples-ec2-instances.md)
+ [在 Amazon EC2 中使用弹性 IP 地址](examples-ec2-elastic-ip.md)
+ [使用区域和可用区](examples-ec2-regions-zones.md)
+ [使用 Amazon EC2 密钥对](examples-ec2-key-pairs.md)
+ [在 Amazon EC2 中使用安全组](examples-ec2-security-groups.md)

# 教程：启动 EC2 实例
<a name="how-to-ec2"></a>

本教程演示如何使用适用于 Java 的 AWS SDK 启动 EC2 实例。

**Topics**
+ [先决条件](#prerequisitesec2)
+ [创建 Amazon EC2 安全组](create-security-group.md)
+ [创建密钥对](create-key-pair.md)
+ [运行 Amazon EC2 实例](run-instance.md)

## 先决条件
<a name="prerequisitesec2"></a>

在开始之前，请确保已创建 AWS 账户并且已设置 AWS 凭证。有关更多信息，请参阅[入门](getting-started.md)。

# 创建 Amazon EC2 安全组
<a name="create-security-group"></a>

## EC2-Classic 将停用
<a name="retiringEC2Classic"></a>

**警告**  
我们将于 2022 年 8 月 15 日停用 EC2-Classic。我们建议您从 EC2-Classic 迁移到 VPC。有关更多信息，请参阅博客文章 [EC2-Classic-Classic Networking is Retiring – Here's How to Prepare](https://aws.amazon.com/blogs/aws/ec2-classic-is-retiring-heres-how-to-prepare/)。

创建一个*安全组*作为虚拟防火墙，控制一个或多个 EC2 实例的网络流量。默认情况下，Amazon EC2 将您的实例与不允许入站流量的安全组关联。可以创建允许您的 EC2 实例接受特定流量的安全组。例如，如果需要连接到 Linux 实例，就必须将安全组配置为允许 SSH 流量。您可以使用 Amazon EC2 控制台或适用于 Java 的 AWS SDK创建安全组。

您可以创建在 EC2-Classic 或 EC2-VPC 中使用的安全组。有关 EC2-Classic 和 EC2-VPC 的更多信息，请参阅《Amazon EC2 用户指南（适用于 Linux 实例）》中的[支持的平台](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-supported-platforms.html)。

有关使用 Amazon EC2 控制台创建安全组的更多信息，请参阅《Amazon EC2 用户指南（适用于 Linux 实例）》中的 [Amazon EC2 安全组](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html)。

1. 创建和初始化 [CreateSecurityGroupRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateSecurityGroupRequest.html) 实例。使用 [withGroupName](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateSecurityGroupRequest.html#withGroupName-java.lang.String-) 方法设置安全组名称，使用 [withDescription](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateSecurityGroupRequest.html#withDescription-java.lang.String-) 方法设置安全组的描述，如下所示：

   ```
   CreateSecurityGroupRequest csgr = new CreateSecurityGroupRequest();
   csgr.withGroupName("JavaSecurityGroup").withDescription("My security group");
   ```

   在您初始化 Amazon EC2 客户端的 AWS 区域内，安全组名称必须是唯一的。必须为安全组的名称和描述使用 US-ASCII 字符。

1. 将请求对象作为参数传递给 [createSecurityGroup](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/AmazonEC2.html#createSecurityGroup-com.amazonaws.services.ec2.model.CreateSecurityGroupRequest-) 方法。该方法返回 [CreateSecurityGroupResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateSecurityGroupResult.html) 对象，如下所示：

   ```
   CreateSecurityGroupResult createSecurityGroupResult =
       amazonEC2Client.createSecurityGroup(csgr);
   ```

   如果您尝试创建与现有安全组具有相同名称的安全组，`createSecurityGroup` 引发异常。

默认情况下，新安全组不允许 Amazon EC2 实例的任何入站流量。要允许入站流量，您必须对安全组传入明确地授权。您可以对单个 IP 地址、IP 地址范围、特定协议以及 TCP/UDP 端口的传入进行授权。

1. 创建并初始化 [IpPermission](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/IpPermission.html) 实例。使用 [withIpv4Ranges](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/IpPermission.html#withIpv4Ranges-java.util.Collection-) 方法可以设置授权传入的 IP 地址范围，使用 [withIpProtocol](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/IpPermission.html#withIpProtocol-java.lang.String-) 方法可以设置 IP 协议。使用 [withFromPort](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/IpPermission.html#withFromPort-java.lang.Integer-) 和 [withToPort](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/IpPermission.html#withToPort-java.lang.Integer-) 方法可以指定授权传入的端口范围，如下所示：

   ```
   IpPermission ipPermission =
       new IpPermission();
   
   IpRange ipRange1 = new IpRange().withCidrIp("111.111.111.111/32");
   IpRange ipRange2 = new IpRange().withCidrIp("150.150.150.150/32");
   
   ipPermission.withIpv4Ranges(Arrays.asList(new IpRange[] {ipRange1, ipRange2}))
               .withIpProtocol("tcp")
               .withFromPort(22)
               .withToPort(22);
   ```

   必须满足在 `IpPermission` 对象中指定的所有条件，才能允许传入。

   使用 CIDR 表示法指定 IP 地址。如果指定 TCP/UDP 协议，必须提供源端口和目标端口。仅在指定 TCP 或 UDP 时才能授权端口。

1. 创建和初始化 [AuthorizeSecurityGroupIngressRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AuthorizeSecurityGroupEgressRequest.html) 实例。使用 `withGroupName` 方法指定安全组名称，并将之前初始化的 `IpPermission` 对象传递给 [withIpPermissions](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AuthorizeSecurityGroupEgressRequest.html#withIpPermissions-com.amazonaws.services.ec2.model.IpPermission…​-) 方法，如下所示：

   ```
   AuthorizeSecurityGroupIngressRequest authorizeSecurityGroupIngressRequest =
       new AuthorizeSecurityGroupIngressRequest();
   
   authorizeSecurityGroupIngressRequest.withGroupName("JavaSecurityGroup")
                                       .withIpPermissions(ipPermission);
   ```

1. 将请求对象传递给 [authorizeSecurityGroupIngress](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/AmazonEC2Client.html#authorizeSecurityGroupIngress-com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest-) 方法，如下所示：

   ```
   amazonEC2Client.authorizeSecurityGroupIngress(authorizeSecurityGroupIngressRequest);
   ```

   如果您使用已授权传入的 IP 地址调用 `authorizeSecurityGroupIngress`，该方法引发异常。创建和初始化新的 `IpPermission` 对象，对不同 IP、端口和协议授权传入，然后调用 `AuthorizeSecurityGroupIngress`。

只要调用 [authorizeSecurityGroupIngress](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/AmazonEC2Client.html#authorizeSecurityGroupIngress-com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest-) 或 [authorizeSecurityGroupEgress](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/AmazonEC2Client.html#authorizeSecurityGroupEgress-com.amazonaws.services.ec2.model.AuthorizeSecurityGroupEgressRequest-) 方法，一条规则就会添加到安全组中。

# 创建密钥对
<a name="create-key-pair"></a>

启动 EC2 实例时必须指定密钥对，然后在连接到实例时指定密钥对的私有密钥。您可以创建密钥对，也可以使用在启动其他实例时使用的现有密钥对。有关更多信息，请参阅《Amazon EC2 用户指南（适用于 Linux 实例）》中的 [Amazon EC2 密钥对](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html)。

1. 创建并启动 [CreateKeyPairRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateKeyPairRequest.html) 实例。使用 [withKeyName](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateKeyPairRequest.html#withKeyName-java.lang.String-) 方法设置密钥对名称，如下所示：

   ```
   CreateKeyPairRequest createKeyPairRequest = new CreateKeyPairRequest();
   
   createKeyPairRequest.withKeyName(keyName);
   ```
**重要**  
密钥对名称必须是唯一的。如果您尝试创建的密钥对名称与现有密钥对相同，将引发异常。

1. 将请求对象传送到 [createKeyPair](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/AmazonEC2.html#createKeyPair-com.amazonaws.services.ec2.model.CreateKeyPairRequest--) 方法。该方法返回 [CreateKeyPairResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateKeyPairResult.html) 实例，如下所示：

   ```
   CreateKeyPairResult createKeyPairResult =
     amazonEC2Client.createKeyPair(createKeyPairRequest);
   ```

1. 调用结果对象的 [getKeyPair](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateKeyPairResult.html#getKeyPair--) 方法，以获取 [KeyPair](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/KeyPair.html) 对象。调用 `KeyPair` 对象的 [getKeyMaterial](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/KeyPair.html#getKeyMaterial--) 方法，以获取未加密的 PEM 编码私有密钥，如下所示：

   ```
   KeyPair keyPair = new KeyPair();
   
   keyPair = createKeyPairResult.getKeyPair();
   
   String privateKey = keyPair.getKeyMaterial();
   ```

# 运行 Amazon EC2 实例
<a name="run-instance"></a>

使用以下过程从同一个 Amazon 系统映像 (AMI) 启动一个或多个具有相同配置的 EC2 实例。创建 EC2 实例后，您可以检查其状态。在您的 EC2 实例运行后，您可以连接这些实例。

1. 创建并初始化一个 [RunInstancesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RunInstancesRequest.html) 实例。确保您指定的 AMI、密钥对和安全组在您创建客户端对象时指定的区域中存在。

   ```
   RunInstancesRequest runInstancesRequest =
      new RunInstancesRequest();
   
   runInstancesRequest.withImageId("ami-a9d09ed1")
                      .withInstanceType(InstanceType.T1Micro)
                      .withMinCount(1)
                      .withMaxCount(1)
                      .withKeyName("my-key-pair")
                      .withSecurityGroups("my-security-group");
   ```  
 [withImageId](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RunInstancesRequest.html#withImageId-java.lang.String-)   
   + AMI 的 ID。要了解如何查找 Amazon 提供的公用 AMI 或创建您自己的 AMI，请参阅 [ Amazon 系统映像 (AMI)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html)。  
 [withInstanceType](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RunInstancesRequest.html#withInstanceType-java.lang.String-)   
   + 与指定的 AMI 兼容的实例类型。有关更多信息，请参阅《Amazon EC2 用户指南（适用于 Linux 实例）》中的[实例类型](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html)。  
 [withMinCount](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RunInstancesRequest.html#withMinCount-java.lang.Integer-)   
   + 要启动的 EC2 实例的最小数量。如果此数量大于 Amazon EC2 可在目标可用区中启动的实例数，则 Amazon EC2 不会启动任何实例。  
 [withMaxCount](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RunInstancesRequest.html#withMaxCount-java.lang.Integer-)   
   + 要启动的 EC2 实例的最大数量。如果此数量大于 Amazon EC2 可在目标可用区中启动的实例数，则 Amazon EC2 将启动高于 `MinCount` 的最大可能数量的实例。您可以启动的实例数介于 1 和您允许为该实例类型启动的最大实例数之间。有关更多信息，请参阅 Amazon EC2 常见问题中的“我可以在 Amazon EC2 中运行多少个实例？”  
 [withKeyName](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RunInstancesRequest.html#withKeyName-java.lang.String-)   
   + EC2 密钥对的名称。如果您在未指定密钥对的情况下启动实例，则无法连接到该实例。有关更多信息，请参阅[创建密钥对](create-key-pair.md)。  
 [withSecurityGroups](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RunInstancesRequest.html#withSecurityGroups-java.util.Collection-)   
   + 一个或多个安全组。有关更多信息，请参阅[创建 Amazon EC2 安全组](create-security-group.md)。

1. 通过将请求对象传递到 [runInstances](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/AmazonEC2Client.html#runInstances-com.amazonaws.services.ec2.model.RunInstancesRequest-) 方法来启动实例。此方法返回一个 [RunInstancesResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RunInstancesResult.html) 对象，如下所示：

   ```
   RunInstancesResult result = amazonEC2Client.runInstances(
                                 runInstancesRequest);
   ```

在您的实例运行后，可使用您的密钥对连接到该实例。有关更多信息，请参阅《Amazon EC2 用户指南（适用于 Linux 实例）》中的[连接到您的 Linux 实例](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstances.html)。

# 使用 IAM 角色授予对 Amazon EC2 上的 AWS 资源的访问权
<a name="java-dg-roles"></a>

必须通过使用由 AWS 颁发的凭证对发送到 Amazon Web Services (AWS) 的所有请求进行加密签名。可以使用 *IAM 角色* 方便地授予对 Amazon EC2 实例上的 AWS 资源的安全访问权。

本主题介绍如何将 IAM 角色与 Amazon EC2 上运行的 Java SDK 应用程序结合使用。有关 IAM 实例的更多信息，请参阅《Amazon EC2 用户指南（适用于 Linux 实例）》中的[适用于 Amazon EC2 的 IAM 角色](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)。

## 默认提供程序链和 EC2 实例配置文件
<a name="default-provider-chain"></a>

如果您的应用程序使用默认构造函数创建 AWS 客户端，则该客户端将按照以下顺序使用*默认凭证提供程序链* 搜索凭证：

1. Java 系统属性：`aws.accessKeyId` 和 `aws.secretKey`。

1. 系统环境变量：`AWS_ACCESS_KEY_ID` 和 `AWS_SECRET_ACCESS_KEY`。

1. 默认凭证文件 (在不同平台上该文件位于不同位置)。

1. 如果已设置 `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` 环境变量且安全管理器有权访问该变量，则为通过 Amazon EC2 容器服务传递的凭证。

1. *实例配置文件凭证*，包含在与 EC2 实例的 IAM 角色关联的实例元数据中。

1. 来自环境或容器的 Web 身份令牌凭证。

只有在对 Amazon EC2 实例运行应用程序时，默认提供程序链中的*实例配置文件凭证* 步骤才可用，但在处理 Amazon EC2 实例时，该步骤能够最大限度地简化使用过程并提高安全性。您还可以将 [InstanceProfileCredentialsProvider](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/auth/InstanceProfileCredentialsProvider.html) 实例直接传递给客户端构造函数，这样无需执行整个默认提供程序链即可获取实例配置文件凭证。

例如：

```
AmazonS3 s3 = AmazonS3ClientBuilder.standard()
              .withCredentials(new InstanceProfileCredentialsProvider(false))
              .build();
```

在使用该方法时，SDK 在其实例配置文件中，检索与 Amazon EC2 实例的关联 IAM 角色的关联凭证具有相同权限的临时 AWS 凭证。尽管这些凭证是临时凭证，而且最终会过期，但 `InstanceProfileCredentialsProvider` 会定期为您刷新它们，保证您收到的凭证可继续访问 AWS。

**重要**  
*仅* 在以下情况下执行自动凭证刷新：您使用默认客户端构造函数 (它会创建其自身的 `InstanceProfileCredentialsProvider` 作为默认提供程序链的内容) 时；或者您将 `InstanceProfileCredentialsProvider` 实例直接传递给客户端构造函数时。如果您使用其他方法获取或传送实例配置文件凭证，您将负责检查和刷新过期凭证。

如果客户端构造函数使用凭证提供程序链找不到凭证，它会引发 [AmazonClientException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/AmazonClientException.html)。

## 演练：将 IAM 角色用于 EC2 实例
<a name="roles-walkthrough"></a>

以下演练将介绍如何使用 IAM 角色从 Amazon S3 中检索对象以管理访问。

### 创建 IAM 角色
<a name="java-dg-create-the-role"></a>

创建授予对 Amazon S3 的只读访问权的 IAM 角色。

1. 打开 [IAM 管理控制台](https://console.aws.amazon.com/iam/home)。

1. 在导航窗格中，选择 **Roles** 和 **Create New Role**。

1. 输入角色名称，然后选择 **Next Step**。请记住此名称，因为在启动 Amazon EC2 实例时会用到它。

1. 在**选择角色类型**页面的 **AWS 服务 角色**下，选择 **Amazon EC2**。

1. 在**设置权限**页面的**选择策略模板**下，选择 **Amazon S3 只读访问权限**，然后选择**下一步**。

1. 在 **Review** 页面上，选择 **Create Role**。

### 启动 EC2 实例并指定您的 IAM 角色
<a name="java-dg-launch-ec2-instance-with-instance-profile"></a>

您可通过 Amazon EC2 控制台或适用于 Java 的 AWS SDK，使用 IAM 角色启动 Amazon EC2 实例。
+ 要使用控制台启动 Amazon EC2 实例，请按照《Amazon EC2 用户指南（适用于 Linux 实例）》[Amazon EC2 Linux 实例入门](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html)中的说明操作。

  到达**核查实例启动**页面时，选择**编辑实例详细信息**。在 **IAM 角色**中，选择您之前创建的 IAM 角色。按指示完成该过程。
**注意**  
您需要创建或使用现有安全组和密钥对，才能连接到该实例。
+ 要使用适用于 Java 的 AWS SDK 通过 IAM 角色启动 Amazon EC2 实例，请参阅[运行 Amazon EC2 实例](run-instance.md)。

### 创建您的应用程序
<a name="java-dg-remove-the-credentials"></a>

让我们来构建在 EC2 实例上运行的示例应用程序。首先，创建一个目录来用于保存教程文件 (例如，`GetS3ObjectApp`)。

然后，将适用于 Java 的 AWS SDK 库复制到新创建的目录中。如果已将适用于 Java 的 AWS SDK下载到 `~/Downloads` 目录中，可以使用以下命令进行复制：

```
cp -r ~/Downloads/aws-java-sdk-{1.7.5}/lib .
cp -r ~/Downloads/aws-java-sdk-{1.7.5}/third-party .
```

打开一个新文件，将其命名为 `GetS3Object.java` 并添加以下代码：

```
import java.io.*;

import com.amazonaws.auth.*;
import com.amazonaws.services.s3.*;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;

public class GetS3Object {
  private static final String bucketName = "text-content";
  private static final String key = "text-object.txt";

  public static void main(String[] args) throws IOException
  {
    AmazonS3 s3Client = AmazonS3ClientBuilder.defaultClient();

    try {
      System.out.println("Downloading an object");
      S3Object s3object = s3Client.getObject(
          new GetObjectRequest(bucketName, key));
      displayTextInputStream(s3object.getObjectContent());
    }
    catch(AmazonServiceException ase) {
      System.err.println("Exception was thrown by the service");
    }
    catch(AmazonClientException ace) {
      System.err.println("Exception was thrown by the client");
    }
  }

  private static void displayTextInputStream(InputStream input) throws IOException
  {
    // Read one text line at a time and display.
    BufferedReader reader = new BufferedReader(new InputStreamReader(input));
    while(true)
    {
      String line = reader.readLine();
      if(line == null) break;
      System.out.println( "    " + line );
    }
    System.out.println();
  }
}
```

打开一个新文件，将其命名为 `build.xml` 并添加以下行：

```
<project name="Get {S3} Object" default="run" basedir=".">
  <path id="aws.java.sdk.classpath">
    <fileset dir="./lib" includes="**/*.jar"/>
    <fileset dir="./third-party" includes="**/*.jar"/>
    <pathelement location="lib"/>
    <pathelement location="."/>
  </path>

  <target name="build">
  <javac debug="true"
    includeantruntime="false"
    srcdir="."
    destdir="."
    classpathref="aws.java.sdk.classpath"/>
  </target>

  <target name="run" depends="build">
    <java classname="GetS3Object" classpathref="aws.java.sdk.classpath" fork="true"/>
  </target>
</project>
```

构建并运行修改后的程序。请注意，该程序中未存储凭证。所以，除非您已经指定 AWS 凭证，否则代码会引发 `AmazonServiceException`。例如：

```
$ ant
Buildfile: /path/to/my/GetS3ObjectApp/build.xml

build:
  [javac] Compiling 1 source file to /path/to/my/GetS3ObjectApp

run:
   [java] Downloading an object
   [java] AmazonServiceException

BUILD SUCCESSFUL
```

### 传输已编译的程序到您的 EC2 实例
<a name="java-dg-transfer-compiled-program-to-ec2-instance"></a>

使用安全复制 (Amazon EC2 ** ``)，将程序连同 ** 库传输到适用于 Java 的 AWS SDK 实例。该命令序列与以下序列相似。

```
scp -p -i {my-key-pair}.pem GetS3Object.class ec2-user@{public_dns}:GetS3Object.class
scp -p -i {my-key-pair}.pem build.xml ec2-user@{public_dns}:build.xml
scp -r -p -i {my-key-pair}.pem lib ec2-user@{public_dns}:lib
scp -r -p -i {my-key-pair}.pem third-party ec2-user@{public_dns}:third-party
```

**注意**  
根据您使用的 Linux 版本，*用户名* 可能是“ec2-user”、“root”或“ubuntu”。要获取实例的公有 DNS 名称，请打开 [EC2 控制台](https://console.aws.amazon.com/ec2/home)并在**描述**选项卡中查找**公有 DNS** 值（例如 `ec2-198-51-100-1.compute-1.amazonaws.com`）。

在上述命令中：
+  `GetS3Object.class` 是已编译的程序
+  `build.xml` 是用于构建和运行您的程序的 Ant 文件
+ `lib` 和 `third-party` 目录是适用于 Java 的 AWS SDK中对应的库文件夹。
+ `-r` 开关指示 `scp` 应该对`library`版本的 `third-party` 和 适用于 Java 的 AWS SDK 目录中的所有内容以递归方式进行复制。
+ `-p` 开关指示 `scp` 在将源文件复制到目标位置时，应保留对应文件的权限。
**注意**  
`-p` 开关仅适用于 Linux、macOS 或 Unix。如果您从 Windows 中复制文件，可能需要使用以下命令在实例上修复文件权限：

```
chmod -R u+rwx GetS3Object.class build.xml lib third-party
```

### 在 EC2 实例上运行示例程序
<a name="java-dg-run-the-program"></a>

要运行程序，请连接到 Amazon EC2 实例。有关更多信息，请参阅《Amazon EC2 用户指南（适用于 Linux 实例）》中的[连接到您的 Linux 实例](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstances.html)。

如果 **` ant ` 在您的实例上不可用，请使用以下命令安装它：**

```
sudo yum install ant
```

然后使用 `ant` 运行程序，如下所示：

```
ant run
```

该程序会将 Amazon S3 对象的内容写入命令窗口。

# 教程：Amazon EC2 竞价型实例
<a name="tutorial-spot-instances-java"></a>

## 概览
<a name="tutor-spot-java-overview"></a>

与按需实例价格相比，通过 Spot 实例，您可以对未使用的 Amazon Elastic Compute Cloud (Amazon EC2) 容量进行出价（最高达 90%），并在出价高于当前 *Spot 价格* 时运行您购买的实例。根据供应和需求情况，Amazon EC2 会定期更改 Spot 价格；出价达到或超过 Spot 价格的客户可获得可用的 Spot 实例。就像按需实例和预留实例， Spot 实例为您提供了另一种获得更多计算能力的选择。

Spot 实例可以大幅降低您用于批量处理、科学研究、图像处理、视频编码、数据和 Web 检索、财务分析和测试的 Amazon EC2 成本。除此之外，在不急需容量的情况下， Spot 实例还能让您获得大量的附加容量。

如要使用 Spot 实例，您就需要置入一个 Spot 实例请求，以便指定您愿意支付的每个实例每小时的最高价格；这就是您的竞价。如果您的最高出价超出当前的 Spot 价格，则会满足您的请求，您的实例将会运行，直到您选择终止它们或 Spot 价格增长到高于您的最高价格（以先到者为准）。

请务必记住：
+ 您每小时支付的价格通常低于您的出价。随着请求的接收和现有供应的变化，Amazon EC2 会定期调整 Spot 价格。在该期间内，无论每个人的最高出价是否更高，它们支付的 Spot 价格都是相同的。因此，您的支付要低于您的出价，但永远不会支付超过您的出价。
+ 如果您正在运行 Spot 实例，而您的出价不再达到或高于当前的 Spot 价格，则您的实例将会终止。这意味着，您要确保工作负载和应用程序足够灵活，以便利用这一机会性的容量。

运行时，Spot 实例的操作方式与其他 Amazon EC2 实例完全相同，而且同其他 Amazon EC2 实例一样，当您不再需要 Spot 实例时可以终止它们。如果终止了实例，您需要为不满一小时的时间付费（与按需或预留实例相同）。不过，如果 Spot 价格超出您的最高价格，且 Amazon EC2 终止了您的实例，则您无需对任何不满一小时的使用时间付费。

本教程介绍如何使用适用于 Java 的 AWS SDK 执行以下操作。
+ 提交一个 Spot 请求
+ 判定何时执行该 Spot 请求
+ 取消该 Spot 请求
+ 终止相关实例

## 先决条件
<a name="tutor-spot-java-prereq"></a>

要使用此指南，您必须已安装适用于 Java 的 AWS SDK 并且已满足其基本安装先决条件。有关更多信息，请参阅[设置适用于 Java 的 AWS SDK](setup-install.md)。

## 第 1 步：设置您的证书
<a name="tutor-spot-java-credentials"></a>

要开始使用此代码示例，您需要设置 AWS 凭证。有关具体操作说明，请参阅[设置用于开发的 AWS 凭证和区域](setup-credentials.md)。

**注意**  
建议您使用 IAM 用户凭证来提供这些值。有关更多信息，请参阅[注册 AWS 并创建 IAM 用户](signup-create-iam-user.md)。

您既然已配置好了您的设置，现在就可以使用示例中的代码开始了。

## 第 2 步：设置安全组
<a name="tutor-spot-java-sg"></a>

一个*安全组*可作为一个控制流量进入和流出实例组的防火墙。默认情况下，实例开始运行时没有配置任何安全组，这就意味着，从任何 TCP 端口传入的 IP 流量都将被拒绝。因此，在提交 Spot 请求前，我们会设置一个安全组，以允许必要的网络流量传入。出于本教程的目的，我们将创建一个名为“GettingStarted”的新安全组，以允许从您正在运行的应用程序的 IP 地址传入 Secure Shell (SSH) 流量。要设置一个新的安全组，需要包含或运行下列通过编程的方式来设置安全组的代码示例。

创建 `AmazonEC2` 客户端数据元之后，我们会创建一个名为“GettingStarted”的`CreateSecurityGroupRequest`数据元以及对安全组的描述。接下来，我们将调用`ec2.createSecurityGroup` API 来创建安全组。

为访问安全组，我们将使用本地电脑子网的 CIDR 表示的 IP 地址范围创建一个 `ipPermission` 数据元，IP 地址的后缀“/10”指明了该指定 IP 地址的子网。我们还为 `ipPermission` 数据元配置了 TCP 协议和端口 22 (SSH)。最后一步是使用我们的安全组名称和 `ec2.authorizeSecurityGroupIngress` 数据元来调用 `ipPermission`。

```
// Create the AmazonEC2 client so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

// Create a new security group.
try {
    CreateSecurityGroupRequest securityGroupRequest = new CreateSecurityGroupRequest("GettingStartedGroup", "Getting Started Security Group");
    ec2.createSecurityGroup(securityGroupRequest);
} catch (AmazonServiceException ase) {
    // Likely this means that the group is already created, so ignore.
    System.out.println(ase.getMessage());
}

String ipAddr = "0.0.0.0/0";

// Get the IP of the current host, so that we can limit the Security
// Group by default to the ip range associated with your subnet.
try {
    InetAddress addr = InetAddress.getLocalHost();

    // Get IP Address
    ipAddr = addr.getHostAddress()+"/10";
} catch (UnknownHostException e) {
}

// Create a range that you would like to populate.
ArrayList<String> ipRanges = new ArrayList<String>();
ipRanges.add(ipAddr);

// Open up port 22 for TCP traffic to the associated IP
// from above (e.g. ssh traffic).
ArrayList<IpPermission> ipPermissions = new ArrayList<IpPermission> ();
IpPermission ipPermission = new IpPermission();
ipPermission.setIpProtocol("tcp");
ipPermission.setFromPort(new Integer(22));
ipPermission.setToPort(new Integer(22));
ipPermission.setIpRanges(ipRanges);
ipPermissions.add(ipPermission);

try {
    // Authorize the ports to the used.
    AuthorizeSecurityGroupIngressRequest ingressRequest =
        new AuthorizeSecurityGroupIngressRequest("GettingStartedGroup",ipPermissions);
    ec2.authorizeSecurityGroupIngress(ingressRequest);
} catch (AmazonServiceException ase) {
    // Ignore because this likely means the zone has
    // already been authorized.
    System.out.println(ase.getMessage());
}
```

请注意，要创建一个新的安全组，您只需要运行一次此应用程序。

您还可以使用 AWS Toolkit for Eclipse 创建安全组。有关更多信息，请参阅[通过 AWS Cost Explorer 管理安全组](https://docs.aws.amazon.com/toolkit-for-eclipse/v1/user-guide/tke-sg.html)。

## 步骤 3：提交您的 Spot 请求
<a name="tutor-spot-java-submit"></a>

为了提交一个 Spot 请求，您首先需要确定该实例类型，Amazon 系统映像 (AMI)，和您要使用的最高出价。还须包括我们先前配置好的安全组，这样一来，如果需要的话，您就可以登录到该实例中了。

有几个实例类型可供选择；请转到 Amazon EC2 实例类型获取完整列表。在本教程中，我们将使用最便宜的实例类型 t1.micro。下一步是确定我们想用的 AMI 类型。在本教程中，我们使用的是最新版的 Amazon Linux AMI，即 ami-a9d09ed1。最新的 AMI 可能会随时间而改变，但您始终可以通过执行以下步骤来确定最新版的 AMI：

1. 打开 [Amazon EC2 管理控制台](https://console.aws.amazon.com/ec2/home)。

1. 选择 **Launch Instance (启动实例)** 按钮。

1. 第一个窗口将显示可用的 AMI。每个 AMI 标题旁边都列出了 AMI ID。或者，您也可以使用 `DescribeImages` API，但该命令的使用不在本教程的范围之内。

有很多方法可以竞价 Spot 实例，如要大致了解各种方法，您应当观看[对 Spot 实例出价](https://www.youtube.com/watch?v=WD9N73F3Fao&feature=player_embedded)视频。然而，为了入门，我们将介绍三种常见的策略：确保成本低于按需定价的竞价；基于所得计算值的竞价；以便尽可能快地获取计算能力的竞价。
+  *降低成本至低于按需实例*您需要进行花费数小时或数天的批处理工作。然而，您可以灵活调整启动和完成时间。您希望看到是否以较低的成本完成了按需实例。您可以通过使用 AWS 管理控制台或 Amazon EC2 API 来检查各个类型实例的 Spot 价格历史记录。如需更多信息，请转到[查看 Spot 价格历史记录](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-spot-instances-history.html)。在您分析了给定可用区内所需实例类型的价格记录之后，您有两种可供选择的方法进行竞价：
  + 您可以在现货价格范围（这仍然低于按需定价）的上端竞价，预测您单次现货请求很有可能会达成，并运行足够的连续计算时间来完成此项工作。
  + 或者，您可以通过按需实例价格的百分比形式，指定您愿意为 Spot 实例支付的金额，并计划将持久请求期间启动的许多实例结合起来。如果超过指定价格，则 Spot 实例将终止。（在本教程之后我们会介绍如何自动运行该任务。）
+  *支付不超过该结果的值*您需要进行数据处理工作。您将会对该工作的结果有一个很好的了解，以便于能够让您知道在计算成本方面它们的价值。当您分析了实例类型的 Spot 价格记录之后，选择一个计算时间成本不高于该工作结果成本的竞价。由于 Spot 价格的波动，该价格可能会达到或低于您的竞价，所以您要创建一个持久出价，并允许它间歇运行。
+  *快速获取计算容量*您对附加容量有一个无法预料的短期需求，该容量不能通过按需实例获取。当您分析了实例类型的 Spot 价格记录之后，您出价高于历史最高价格，以便提供一个高的能很快执行实例的可能性，并继续计算，直到完成实例。

在选择竞价之后，您可以请求一个 Spot 实例。考虑到本教程的目的，我们将以按需定价来出价 (0.03 US)，以便能最大化执行出价的机率。您可以通过进入 Amazon EC2 定价页面来确定可用实例的类型和这些实例的按需价格。当 Spot 实例在运行时，您将支付实例运行期间生效的 Spot 价格。Spot 实例的价格由 Amazon EC2 设置，并根据 Spot 实例容量的长期供求趋势逐步调整。您还可以指定您愿意为 Spot 实例支付的金额作为按需实例价格的百分比。要请求 Spot 实例，您只需使用先前选择的参数来构建请求。首先，我们创建一个`RequestSpotInstanceRequest`数据元。数据元的请求需要要启动的实例数量及其竞价。此外，您还需要设置`LaunchSpecification`该请求，其中包括实例类型、AMI ID，和要使用的安全组。在填写好该请求后，您可以调用该数据元上的`requestSpotInstances`方法`AmazonEC2Client`。以下示例演示了如何请求一个 Spot 实例。

```
// Create the AmazonEC2 client so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

// Initializes a Spot Instance Request
RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest();

// Request 1 x t1.micro instance with a bid price of $0.03.
requestRequest.setSpotPrice("0.03");
requestRequest.setInstanceCount(Integer.valueOf(1));

// Setup the specifications of the launch. This includes the
// instance type (e.g. t1.micro) and the latest Amazon Linux
// AMI id available. Note, you should always use the latest
// Amazon Linux AMI id or another of your choosing.
LaunchSpecification launchSpecification = new LaunchSpecification();
launchSpecification.setImageId("ami-a9d09ed1");
launchSpecification.setInstanceType(InstanceType.T1Micro);

// Add the security group to the request.
ArrayList<String> securityGroups = new ArrayList<String>();
securityGroups.add("GettingStartedGroup");
launchSpecification.setSecurityGroups(securityGroups);

// Add the launch specifications to the request.
requestRequest.setLaunchSpecification(launchSpecification);

// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);
```

此代码的运行将启动一个新的 Spot 实例请求。还有其他可用来配置 Spot 请求的选择。要了解更多信息，请访问[教程：高级 Amazon EC2 竞价型实例请求管理](tutorial-spot-adv-java.md)或《适用于 Java 的 AWS SDK API Reference》中的 [RequestSpotInstances](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RequestSpotInstancesRequest.html) 类。

**注意**  
您需为任何已启动的 Spot 实例付费，因此，请确保您取消了任何请求并终止了任何已启动的实例，以便减少所有相关费用。

## 步骤 4：确定 Spot 请求的状态
<a name="tutor-spot-java-request-state"></a>

下一步是，要一直等到在进行最后一步之前、Spot 请求达到“活跃”状态时再创建代码。为了确定 Spot 请求的状态，我们轮询了[ describeSpotInstanceRequests](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/AmazonEC2Client.html#describeSpotInstanceRequests)方法来确定要监视的 Spot 请求 ID 的状态。

第 2 步中创建的请求 ID 内嵌在该`requestSpotInstances`请求响应中。以下示例代码显示了如何从`requestSpotInstances`响应中收集请求 ID 和如何用它们填写一个`ArrayList`。

```
// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);
List<SpotInstanceRequest> requestResponses = requestResult.getSpotInstanceRequests();

// Setup an arraylist to collect all of the request ids we want to
// watch hit the running state.
ArrayList<String> spotInstanceRequestIds = new ArrayList<String>();

// Add all of the request ids to the hashset, so we can determine when they hit the
// active state.
for (SpotInstanceRequest requestResponse : requestResponses) {
    System.out.println("Created Spot Request: "+requestResponse.getSpotInstanceRequestId());
    spotInstanceRequestIds.add(requestResponse.getSpotInstanceRequestId());
}
```

为哦了监控您的请求 ID，请调用`describeSpotInstanceRequests`方法来确定该请求的状态。然后循环，直到该请求不处于“打开”的状态。请注意，我们监控的是“打开”这一状态，而不是“活跃”状态，因为如果请求参数有问题，该请求可以直接“关闭”。以下代码示例提供了如何完成此项任务的详细信息。

```
// Create a variable that will track whether there are any
// requests still in the open state.
boolean anyOpen;

do {
    // Create the describeRequest object with all of the request ids
    // to monitor (e.g. that we started).
    DescribeSpotInstanceRequestsRequest describeRequest = new DescribeSpotInstanceRequestsRequest();
    describeRequest.setSpotInstanceRequestIds(spotInstanceRequestIds);

    // Initialize the anyOpen variable to false - which assumes there
    // are no requests open unless we find one that is still open.
    anyOpen=false;

    try {
        // Retrieve all of the requests we want to monitor.
        DescribeSpotInstanceRequestsResult describeResult = ec2.describeSpotInstanceRequests(describeRequest);
        List<SpotInstanceRequest> describeResponses = describeResult.getSpotInstanceRequests();

        // Look through each request and determine if they are all in
        // the active state.
        for (SpotInstanceRequest describeResponse : describeResponses) {
            // If the state is open, it hasn't changed since we attempted
            // to request it. There is the potential for it to transition
            // almost immediately to closed or cancelled so we compare
            // against open instead of active.
        if (describeResponse.getState().equals("open")) {
            anyOpen = true;
            break;
        }
    }
} catch (AmazonServiceException e) {
      // If we have an exception, ensure we don't break out of
      // the loop. This prevents the scenario where there was
      // blip on the wire.
      anyOpen = true;
    }

    try {
        // Sleep for 60 seconds.
        Thread.sleep(60*1000);
    } catch (Exception e) {
        // Do nothing because it woke up early.
    }
} while (anyOpen);
```

运行此代码后， Spot 实例请求会完成或失败，如果失败，将输出一个错误提示到屏幕上。在任一情况下，我们都可以进行下一步，以便清理任何已活跃请求并终止任何正在运行的实例。

## 步骤 5：清理 Spot 请求和实例
<a name="tutor-spot-java-cleaning-up"></a>

最后，我们需要清理请求和实例。重要的是，要取消所有未完成的请求*并*终止所有实例。只取消请求不会终止您的实例，这意味着您需要继续为它们支付费用。如果您终止了实例，那么 Spot 请求可能会被取消，但在某些情况下，例如，如果您使用的是持久出价，那么终止实例则不足以阻止请求重新执行。因此，最好的做法是取消所有已活跃出价并终止所有正在运行的实例。

以下代码演示了如何取消您的请求。

```
try {
    // Cancel requests.
    CancelSpotInstanceRequestsRequest cancelRequest =
       new CancelSpotInstanceRequestsRequest(spotInstanceRequestIds);
    ec2.cancelSpotInstanceRequests(cancelRequest);
} catch (AmazonServiceException e) {
    // Write out any exceptions that may have occurred.
    System.out.println("Error cancelling instances");
    System.out.println("Caught Exception: " + e.getMessage());
    System.out.println("Reponse Status Code: " + e.getStatusCode());
    System.out.println("Error Code: " + e.getErrorCode());
    System.out.println("Request ID: " + e.getRequestId());
}
```

要终止所有挂起的实例，您需要实例 ID 和启动它们的请求。以下代码示例采用了原代码来监控这些实例，并增加了一个存储这些实例 ID 和相关联的`ArrayList`响应的`describeInstance`。

```
// Create a variable that will track whether there are any requests
// still in the open state.
boolean anyOpen;
// Initialize variables.
ArrayList<String> instanceIds = new ArrayList<String>();

do {
   // Create the describeRequest with all of the request ids to
   // monitor (e.g. that we started).
   DescribeSpotInstanceRequestsRequest describeRequest = new DescribeSpotInstanceRequestsRequest();
   describeRequest.setSpotInstanceRequestIds(spotInstanceRequestIds);

   // Initialize the anyOpen variable to false, which assumes there
   // are no requests open unless we find one that is still open.
   anyOpen = false;

   try {
         // Retrieve all of the requests we want to monitor.
         DescribeSpotInstanceRequestsResult describeResult =
            ec2.describeSpotInstanceRequests(describeRequest);

         List<SpotInstanceRequest> describeResponses =
            describeResult.getSpotInstanceRequests();

         // Look through each request and determine if they are all
         // in the active state.
         for (SpotInstanceRequest describeResponse : describeResponses) {
           // If the state is open, it hasn't changed since we
           // attempted to request it. There is the potential for
           // it to transition almost immediately to closed or
           // cancelled so we compare against open instead of active.
           if (describeResponse.getState().equals("open")) {
              anyOpen = true; break;
           }
           // Add the instance id to the list we will
           // eventually terminate.
           instanceIds.add(describeResponse.getInstanceId());
         }
   } catch (AmazonServiceException e) {
      // If we have an exception, ensure we don't break out
      // of the loop. This prevents the scenario where there
      // was blip on the wire.
      anyOpen = true;
   }

    try {
        // Sleep for 60 seconds.
        Thread.sleep(60*1000);
    } catch (Exception e) {
        // Do nothing because it woke up early.
    }
} while (anyOpen);
```

使用存储在`ArrayList`中的实例 ID，通过使用以下代码片段来终止任何正在运行的实例。

```
try {
    // Terminate instances.
    TerminateInstancesRequest terminateRequest = new TerminateInstancesRequest(instanceIds);
    ec2.terminateInstances(terminateRequest);
} catch (AmazonServiceException e) {
    // Write out any exceptions that may have occurred.
    System.out.println("Error terminating instances");
    System.out.println("Caught Exception: " + e.getMessage());
    System.out.println("Reponse Status Code: " + e.getStatusCode());
    System.out.println("Error Code: " + e.getErrorCode());
    System.out.println("Request ID: " + e.getRequestId());
}
```

## 综述
<a name="tutor-spot-java-bring-together"></a>

为了将所有内容组合在一起，我们提供了一个更加面向数据元的方法，该方法结合了上文所示步骤：初始化 EC2 客户端，提交 Spot 请求，确定何时 Spot 请求不再处于开放状态，并清理所有延迟的 Spot 请求和相关实例。我们建立一个执行这些操作的类别，命名为`Requests`。

我们还创建了一个 `GettingStartedApp` 类，为我们执行高级函数调用提供主要方法。具体地，我们对之前所述的数据元`Requests`进行初始化。提交 Spot 实例请求。然后等待 Spot 请求达到“有效”状态。最后，清理这些请求和实例。

可在 [GitHub](https://github.com/aws/aws-sdk-java/tree/master/src/samples/AmazonEC2SpotInstances-GettingStarted) 查看和下载此示例的完整源代码。

恭喜您！您已经完成了用适用于 Java 的 AWS SDK 开发 Spot 实例软件的入门教程。

## 后续步骤
<a name="tutor-spot-java-next"></a>

继续阅览[教程：高级 Amazon EC2 竞价型实例请求管理](tutorial-spot-adv-java.md)。

# 教程：高级 Amazon EC2 竞价型实例请求管理
<a name="tutorial-spot-adv-java"></a>

 Amazon EC2 Spot 实例允许您对未使用的 Amazon EC2 容量出价，并在出价高于当前 *Spot 价格* 的期间运行此类实例。Amazon EC2 基于供给和需求定期更改 Spot 价格。有关竞价型实例的更多信息，请参阅《Amazon EC2 用户指南（适用于 Linux 实例）》中的[竞价型实例](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-spot-instances.html)。

## 先决条件
<a name="tutor-spot-adv-java-prereq"></a>

要使用此指南，您必须已安装适用于 Java 的 AWS SDK 并且已满足其基本安装先决条件。有关更多信息，请参阅[设置适用于 Java 的 AWS SDK](setup-install.md)。

## 设置您的凭证
<a name="tutor-spot-adv-java-credentials"></a>

要开始使用此代码示例，您需要设置 AWS 凭证。有关具体操作说明，请参阅[设置用于开发的 AWS 凭证和区域](setup-credentials.md)。

**注意**  
建议您使用 IAM 用户凭证来提供这些值。有关更多信息，请参阅[注册 AWS 并创建 IAM 用户](signup-create-iam-user.md)。

您既然已配置好了您的设置，现在就可以使用示例中的代码开始了。

## 设置安全组
<a name="tutor-spot-adv-java-sg"></a>

一个安全组可作为一个控制流量进入和流出实例组的防火墙。默认情况下，实例开始运行时没有配置任何安全组，这就意味着，从任何 TCP 端口传入的 IP 流量都将被拒绝。因此，在提交 Spot 请求前，我们会设置一个安全组，以允许必要的网络流量传入。出于本教程的目的，我们将创建一个名为“GettingStarted”的新安全组，以允许从您正在运行的应用程序的 IP 地址传入 Secure Shell (SSH) 流量。要设置一个新的安全组，需要包含或运行下列通过编程的方式来设置安全组的代码示例。

创建 `AmazonEC2` 客户端数据元之后，我们会创建一个名为“GettingStarted”的`CreateSecurityGroupRequest`数据元以及对安全组的描述。接下来，我们将调用`ec2.createSecurityGroup` API 来创建安全组。

为访问安全组，我们将使用本地电脑子网的 CIDR 表示的 IP 地址范围创建一个 `ipPermission` 数据元，IP 地址的后缀“/10”指明了该指定 IP 地址的子网。我们还为 `ipPermission` 数据元配置了 TCP 协议和端口 22 (SSH)。最后一步是使用我们的安全组名称和 `ec2 .authorizeSecurityGroupIngress` 数据元来调用 `ipPermission`。

（以下代码与我们在第一个教程中使用的代码相同。）

```
// Create the AmazonEC2Client object so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.standard()
                    .withCredentials(credentials)
                    .build();

// Create a new security group.
try {
    CreateSecurityGroupRequest securityGroupRequest =
        new CreateSecurityGroupRequest("GettingStartedGroup",
        "Getting Started Security Group");
    ec2.createSecurityGroup(securityGroupRequest);
} catch (AmazonServiceException ase) {
    // Likely this means that the group is already created, so ignore.
    System.out.println(ase.getMessage());
}

String ipAddr = "0.0.0.0/0";

// Get the IP of the current host, so that we can limit the Security Group
// by default to the ip range associated with your subnet.
try {
    // Get IP Address
    InetAddress addr = InetAddress.getLocalHost();
    ipAddr = addr.getHostAddress()+"/10";
}
catch (UnknownHostException e) {
    // Fail here...
}

// Create a range that you would like to populate.
ArrayList<String> ipRanges = new ArrayList<String>();
ipRanges.add(ipAddr);

// Open up port 22 for TCP traffic to the associated IP from
// above (e.g. ssh traffic).
ArrayList<IpPermission> ipPermissions = new ArrayList<IpPermission> ();
IpPermission ipPermission = new IpPermission();
ipPermission.setIpProtocol("tcp");
ipPermission.setFromPort(new Integer(22));
ipPermission.setToPort(new Integer(22));
ipPermission.setIpRanges(ipRanges);
ipPermissions.add(ipPermission);

try {
    // Authorize the ports to the used.
    AuthorizeSecurityGroupIngressRequest ingressRequest =
        new AuthorizeSecurityGroupIngressRequest(
            "GettingStartedGroup",ipPermissions);
    ec2.authorizeSecurityGroupIngress(ingressRequest);
}
catch (AmazonServiceException ase) {
    // Ignore because this likely means the zone has already
    // been authorized.
    System.out.println(ase.getMessage());
}
```

您可以在 `advanced.CreateSecurityGroupApp.java` 代码示例中查看整个代码示例。请注意，要创建一个新的安全组，您只需要运行一次此应用程序。

**注意**  
您还可以使用 AWS Toolkit for Eclipse 创建安全组。有关更多信息，请参阅《AWS Toolkit for Eclipse User Guide》中的 [Managing Security Groups from AWS Cost Explorer](https://docs.aws.amazon.com/toolkit-for-eclipse/v1/user-guide/tke-sg.html)。

## 详细 Spot 实例请求创建选项
<a name="tutor-spot-adv-req-opts"></a>

正如我们在[教程：Amazon EC2 竞价型实例](tutorial-spot-instances-java.md)中所介绍的，您需要通过实例类型、亚马逊机器映像 (AMI) 和最高竞标价格来创建您的请求。

让我们从创建 `RequestSpotInstanceRequest` 对象开始。请求数据元需要您所需的实例数量和竞标价格。此外，我们需要为请求设置 `LaunchSpecification`，包括实例类型、AMI ID 和您需要使用的安全组。填入请求后，我们将在 `requestSpotInstances` 数据元上调用 `AmazonEC2Client` 方法。以下是如何申请 Spot 实例的一个示例。

（以下代码与我们在第一个教程中使用的代码相同。）

```
// Create the AmazonEC2 client so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

// Initializes a Spot Instance Request
RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest();

// Request 1 x t1.micro instance with a bid price of $0.03.
requestRequest.setSpotPrice("0.03");
requestRequest.setInstanceCount(Integer.valueOf(1));

// Set up the specifications of the launch. This includes the
// instance type (e.g. t1.micro) and the latest Amazon Linux
// AMI id available. Note, you should always use the latest
// Amazon Linux AMI id or another of your choosing.
LaunchSpecification launchSpecification = new LaunchSpecification();
launchSpecification.setImageId("ami-a9d09ed1");
launchSpecification.setInstanceType(InstanceType.T1Micro);

// Add the security group to the request.
ArrayList<String> securityGroups = new ArrayList<String>();
securityGroups.add("GettingStartedGroup");
launchSpecification.setSecurityGroups(securityGroups);

// Add the launch specification.
requestRequest.setLaunchSpecification(launchSpecification);

// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult =
    ec2.requestSpotInstances(requestRequest);
```

## 持久性请求和一次性请求
<a name="tutor-spot-adv-persist-v-one"></a>

建立一个 Spot 请求时，您可以指定几个可选参数。首先是您的请求是一次性的还是持久性的。默认情况下，一般是一次性请求。一次性请求可以只执行一次，请求实例终止后，请求将被关闭。同一请求中没有 Spot 实例运行的任何时候，持久性请求都被视为已完成。要指定请求的类型，您只需要设置 Spot 请求的类型。您可以使用以下代码完成设置。

```
// Retrieves the credentials from an AWSCredentials.properties file.
AWSCredentials credentials = null;
try {
    credentials = new PropertiesCredentials(
        GettingStartedApp.class.getResourceAsStream("AwsCredentials.properties"));
}
catch (IOException e1) {
    System.out.println(
        "Credentials were not properly entered into AwsCredentials.properties.");
    System.out.println(e1.getMessage());
    System.exit(-1);
}

// Create the AmazonEC2 client so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

// Initializes a Spot Instance Request
RequestSpotInstancesRequest requestRequest =
    new RequestSpotInstancesRequest();

// Request 1 x t1.micro instance with a bid price of $0.03.
requestRequest.setSpotPrice("0.03");
requestRequest.setInstanceCount(Integer.valueOf(1));

// Set the type of the bid to persistent.
requestRequest.setType("persistent");

// Set up the specifications of the launch. This includes the
// instance type (e.g. t1.micro) and the latest Amazon Linux
// AMI id available. Note, you should always use the latest
// Amazon Linux AMI id or another of your choosing.
LaunchSpecification launchSpecification = new LaunchSpecification();
launchSpecification.setImageId("ami-a9d09ed1");
launchSpecification.setInstanceType(InstanceType.T1Micro);

// Add the security group to the request.
ArrayList<String> securityGroups = new ArrayList<String>();
securityGroups.add("GettingStartedGroup");
launchSpecification.setSecurityGroups(securityGroups);

// Add the launch specification.
requestRequest.setLaunchSpecification(launchSpecification);

// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult =
    ec2.requestSpotInstances(requestRequest);
```

## 限制请求的持续时间
<a name="tutor-spot-adv-validity-period"></a>

您还可以有选择地指定您的请求持续有效的时长。您可以指定有效期开始和结束的时间。默认情况下，从创建那一刻开始，系统将默认执行 Spot 请求，直到该请求完成或被取消。然而，如果您有需要，您可以限制有效期。以下代码显示了如何指定有效期的示例。

```
// Create the AmazonEC2 client so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

// Initializes a Spot Instance Request
RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest();

// Request 1 x t1.micro instance with a bid price of $0.03.
requestRequest.setSpotPrice("0.03");
requestRequest.setInstanceCount(Integer.valueOf(1));

// Set the valid start time to be two minutes from now.
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, 2);
requestRequest.setValidFrom(cal.getTime());

// Set the valid end time to be two minutes and two hours from now.
cal.add(Calendar.HOUR, 2);
requestRequest.setValidUntil(cal.getTime());

// Set up the specifications of the launch. This includes
// the instance type (e.g. t1.micro)

// and the latest Amazon Linux AMI id available.
// Note, you should always use the latest Amazon
// Linux AMI id or another of your choosing.
LaunchSpecification launchSpecification = new LaunchSpecification();
launchSpecification.setImageId("ami-a9d09ed1");
launchSpecification.setInstanceType("t1.micro");

// Add the security group to the request.
ArrayList<String> securityGroups = new ArrayList<String>();
securityGroups.add("GettingStartedGroup");
launchSpecification.setSecurityGroups(securityGroups);

// Add the launch specification.
requestRequest.setLaunchSpecification(launchSpecification);

// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);
```

## 将您的 Amazon EC2 Spot 实例请求分组
<a name="tutor-spot-adv-grouping"></a>

您可以选择几种不同方法为您的 Spot 实例请求分组。我们来看看使用启动组、可用区组和置放组的好处。

如果您想要确保您的 Spot 实例全部一起启动和终止，您可以选择利用启动组。启动组是将一系列竞价分在一组的标签。启动组内的所有实例都一起启动和终止。请注意，如果启动组内的实例已经完成了，不能保证同一启动组新启动的实例也随之完成。以下代码示例显示了如何设置启动组的示例。

```
// Create the AmazonEC2 client so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

// Initializes a Spot Instance Request
RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest();

// Request 5 x t1.micro instance with a bid price of $0.03.
requestRequest.setSpotPrice("0.03");
requestRequest.setInstanceCount(Integer.valueOf(5));

// Set the launch group.
requestRequest.setLaunchGroup("ADVANCED-DEMO-LAUNCH-GROUP");

// Set up the specifications of the launch. This includes
// the instance type (e.g. t1.micro) and the latest Amazon Linux
// AMI id available. Note, you should always use the latest
// Amazon Linux AMI id or another of your choosing.
LaunchSpecification launchSpecification = new LaunchSpecification();
launchSpecification.setImageId("ami-a9d09ed1");
launchSpecification.setInstanceType(InstanceType.T1Micro);

// Add the security group to the request.
ArrayList<String> securityGroups = new ArrayList<String>();
securityGroups.add("GettingStartedGroup");
launchSpecification.setSecurityGroups(securityGroups);

// Add the launch specification.
requestRequest.setLaunchSpecification(launchSpecification);

// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult =
    ec2.requestSpotInstances(requestRequest);
```

如果您要确保请求中的所有实例在同一可用区内启动，而对具体哪个可用区并没有要求，您可以利用可用区组。可用区域组是将一系列同一可用区域内的实例分在一组的标签。共享同一可用区域组并同时完成的所有实例将在同一可用区域内开始运行。以下是如何设置可用区域组的一个示例。

```
// Create the AmazonEC2 client so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

// Initializes a Spot Instance Request
RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest();

// Request 5 x t1.micro instance with a bid price of $0.03.
requestRequest.setSpotPrice("0.03");
requestRequest.setInstanceCount(Integer.valueOf(5));

// Set the availability zone group.
requestRequest.setAvailabilityZoneGroup("ADVANCED-DEMO-AZ-GROUP");

// Set up the specifications of the launch.  This includes the instance
// type (e.g.  t1.micro) and the latest Amazon Linux AMI id available.
// Note, you should always use the latest Amazon Linux AMI id or another
// of your choosing.
LaunchSpecification launchSpecification = new LaunchSpecification();
launchSpecification.setImageId("ami-a9d09ed1");
launchSpecification.setInstanceType(InstanceType.T1Micro);

// Add the security group to the request.
ArrayList<String> securityGroups = new ArrayList<String>();
securityGroups.add("GettingStartedGroup");
launchSpecification.setSecurityGroups(securityGroups);

// Add the launch specification.
requestRequest.setLaunchSpecification(launchSpecification);

// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult =
    ec2.requestSpotInstances(requestRequest);
```

您可以为您的 Spot 实例指定一个可用区域。以下代码示例为您显示如何设置可用区域。

```
// Create the AmazonEC2 client so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

// Initializes a Spot Instance Request
RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest();

// Request 1 x t1.micro instance with a bid price of $0.03.
requestRequest.setSpotPrice("0.03");
requestRequest.setInstanceCount(Integer.valueOf(1));

// Set up the specifications of the launch. This includes the instance
// type (e.g. t1.micro) and the latest Amazon Linux AMI id available.
// Note, you should always use the latest Amazon Linux AMI id or another
// of your choosing.
LaunchSpecification launchSpecification = new LaunchSpecification();
launchSpecification.setImageId("ami-a9d09ed1");
launchSpecification.setInstanceType(InstanceType.T1Micro);

// Add the security group to the request.
ArrayList<String> securityGroups = new ArrayList<String>();
securityGroups.add("GettingStartedGroup");
launchSpecification.setSecurityGroups(securityGroups);

// Set up the availability zone to use. Note we could retrieve the
// availability zones using the ec2.describeAvailabilityZones() API. For
// this demo we will just use us-east-1a.
SpotPlacement placement = new SpotPlacement("us-east-1b");
launchSpecification.setPlacement(placement);

// Add the launch specification.
requestRequest.setLaunchSpecification(launchSpecification);

// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult =
    ec2.requestSpotInstances(requestRequest);
```

最后，如果您使用的是高性能计算 (HPC) Spot 实例（例如，集群计算实例或集群 GPU 实例），则您可以指定一个*置放群组*。置放组为您提供更低的延迟和实例之间的高带宽连接。以下是如何设置置放组的一个示例。

```
// Create the AmazonEC2 client so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

// Initializes a Spot Instance Request
RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest();

// Request 1 x t1.micro instance with a bid price of $0.03.
requestRequest.setSpotPrice("0.03");
requestRequest.setInstanceCount(Integer.valueOf(1));

// Set up the specifications of the launch. This includes the instance
// type (e.g. t1.micro) and the latest Amazon Linux AMI id available.
// Note, you should always use the latest Amazon Linux AMI id or another
// of your choosing.

LaunchSpecification launchSpecification = new LaunchSpecification();
launchSpecification.setImageId("ami-a9d09ed1");
launchSpecification.setInstanceType(InstanceType.T1Micro);

// Add the security group to the request.
ArrayList<String> securityGroups = new ArrayList<String>();
securityGroups.add("GettingStartedGroup");
launchSpecification.setSecurityGroups(securityGroups);

// Set up the placement group to use with whatever name you desire.
// For this demo we will just use "ADVANCED-DEMO-PLACEMENT-GROUP".
SpotPlacement placement = new SpotPlacement();
placement.setGroupName("ADVANCED-DEMO-PLACEMENT-GROUP");
launchSpecification.setPlacement(placement);

// Add the launch specification.
requestRequest.setLaunchSpecification(launchSpecification);

// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult =
    ec2.requestSpotInstances(requestRequest);
```

本节所显示的所有参数都是可选的。同样重要的是要认识到，这些参数中的大多数（您的出价是一次性还是永久性出价除外）都可能降低出价实现的可能性。因此，只有当您需要的时候才利用这些选择，这很重要。所有前面的代码示例被组合成一个长代码示例，可在 `com.amazonaws.codesamples.advanced.InlineGettingStartedCodeSampleApp.java` 类别中找到。

## 中断或终止发生后，如何持久保存一个根分区
<a name="tutor-spot-adv-persist-root"></a>

管理竞价型实例中断最简单的方法之一是确保定期为您的数据执行到 Amazon Elastic Block Store (Amazon Amazon EBS) 卷的检查点操作。通过定期执行点校验，如果发生中断，您只会丢失上一次点校验后创建的数据（假设中间没有执行其他非幂等操作）。为了使这个过程变得更容易，您可以配置您的 Spot 请求，以确保中断或终止发生时您的根分区不会被删除。在以下如何实现此方案的示例中，我们插入了新代码。

在添加的代码中，我们创建了一个 `BlockDeviceMapping` 对象，并将与其相关联的 Amazon Elastic Block Store (Amazon EBS) 设置到 Amazon EBS 对象，之前我们已对此对象进行配置，如果竞价型实例被终止，此对象 `not` 随之删除。然后，我们将此 `BlockDeviceMapping` 添加到启动说明中所包含的映射的 ArrayList。

```
// Retrieves the credentials from an AWSCredentials.properties file.
AWSCredentials credentials = null;
try {
    credentials = new PropertiesCredentials(
        GettingStartedApp.class.getResourceAsStream("AwsCredentials.properties"));
}
catch (IOException e1) {
    System.out.println(
        "Credentials were not properly entered into AwsCredentials.properties.");
    System.out.println(e1.getMessage());
    System.exit(-1);
}

// Create the AmazonEC2 client so we can call various APIs.
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

// Initializes a Spot Instance Request
RequestSpotInstancesRequest requestRequest = new RequestSpotInstancesRequest();

// Request 1 x t1.micro instance with a bid price of $0.03.
requestRequest.setSpotPrice("0.03");
requestRequest.setInstanceCount(Integer.valueOf(1));

// Set up the specifications of the launch. This includes the instance
// type (e.g. t1.micro) and the latest Amazon Linux AMI id available.
// Note, you should always use the latest Amazon Linux AMI id or another
// of your choosing.
LaunchSpecification launchSpecification = new LaunchSpecification();
launchSpecification.setImageId("ami-a9d09ed1");
launchSpecification.setInstanceType(InstanceType.T1Micro);

// Add the security group to the request.
ArrayList<String> securityGroups = new ArrayList<String>();
securityGroups.add("GettingStartedGroup");
launchSpecification.setSecurityGroups(securityGroups);

// Create the block device mapping to describe the root partition.
BlockDeviceMapping blockDeviceMapping = new BlockDeviceMapping();
blockDeviceMapping.setDeviceName("/dev/sda1");

// Set the delete on termination flag to false.
EbsBlockDevice ebs = new EbsBlockDevice();
ebs.setDeleteOnTermination(Boolean.FALSE);
blockDeviceMapping.setEbs(ebs);

// Add the block device mapping to the block list.
ArrayList<BlockDeviceMapping> blockList = new ArrayList<BlockDeviceMapping>();
blockList.add(blockDeviceMapping);

// Set the block device mapping configuration in the launch specifications.
launchSpecification.setBlockDeviceMappings(blockList);

// Add the launch specification.
requestRequest.setLaunchSpecification(launchSpecification);

// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult =
    ec2.requestSpotInstances(requestRequest);
```

如果您想在启动时重新连接该卷到您的实例中，也可以使用数据块存储设备映射设置。另外，如果您连接了一个非根分区，则可以指定您希望在竞价型实例恢复后连接到该实例的 Amazon Amazon EBS 卷。要实现此功能，您只需指定 `EbsBlockDevice` 数据元中的快照 ID 和 `BlockDeviceMapping` 数据元中的替代设备名称。通过利用数据块存储设备映射，可以让引导实例变得更加容易。

使用根分区来对您的关键数据执行点校验是管理您的实例可能性中断的好方法。有关更多管理可能性中断的方法，请参阅“[Managing Interruption](https://www.youtube.com/watch?feature=player_embedded&v=wcPNnUo60pc)”视频。

## 如何标记您的 Spot 请求和实例
<a name="tutor-spot-adv-tags"></a>

为 Amazon EC2 资源添加标签能简化您的云基础设施管理。某种形式的元数据、标记可用于创建用户友好型名称、增强搜索能力，并改善多个用户之间的协作。您也可以使用标记来自动化脚本和部分进程。要阅读有关为 Amazon EC2 资源添加标签的更多信息，请转至《Amazon EC2 用户指南（适用于 Linux 实例）》中的[使用标签](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html)。

### 添加标签请求
<a name="tagging-requests"></a>

要为您的 Spot 请求添加标签，您需要在提交请求*之后* 为它们添加标签。来自 `requestSpotInstances()` 的返回值将为您提供一个 [RequestSpotInstancesResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RequestSpotInstancesResult.html) 对象，此对象可用于获取 Spot 请求 ID 以便添加标签：

```
// Call the RequestSpotInstance API.
RequestSpotInstancesResult requestResult = ec2.requestSpotInstances(requestRequest);
List<SpotInstanceRequest> requestResponses = requestResult.getSpotInstanceRequests();

// A list of request IDs to tag
ArrayList<String> spotInstanceRequestIds = new ArrayList<String>();

// Add the request ids to the hashset, so we can determine when they hit the
// active state.
for (SpotInstanceRequest requestResponse : requestResponses) {
    System.out.println("Created Spot Request: "+requestResponse.getSpotInstanceRequestId());
    spotInstanceRequestIds.add(requestResponse.getSpotInstanceRequestId());
}
```

在获得 ID 后，您可以通过将请求 ID 添加到 [CreateTagsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateTagsRequest.html) 并调用 Amazon EC2 客户端的 `createTags()` 方法来为请求添加标签：

```
// The list of tags to create
ArrayList<Tag> requestTags = new ArrayList<Tag>();
requestTags.add(new Tag("keyname1","value1"));

// Create the tag request
CreateTagsRequest createTagsRequest_requests = new CreateTagsRequest();
createTagsRequest_requests.setResources(spotInstanceRequestIds);
createTagsRequest_requests.setTags(requestTags);

// Tag the spot request
try {
    ec2.createTags(createTagsRequest_requests);
}
catch (AmazonServiceException e) {
    System.out.println("Error terminating instances");
    System.out.println("Caught Exception: " + e.getMessage());
    System.out.println("Reponse Status Code: " + e.getStatusCode());
    System.out.println("Error Code: " + e.getErrorCode());
    System.out.println("Request ID: " + e.getRequestId());
}
```

### 标记实例
<a name="tagging-instances"></a>

与 Spot 请求本身类似，您只能在创建实例后为其添加标签，此操作将在满足 Spot 请求后 (不再处于*打开* 状态) 立即执行。

您可以通过使用 [DescribeSpotInstanceRequestsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DescribeSpotInstanceRequestsRequest.html) 对象调用 Amazon EC2 客户端的 `describeSpotInstanceRequests()` 方法来检查请求的状态。返回的 [DescribeSpotInstanceRequestsResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DescribeSpotInstanceRequestsResult.html) 对象包含 [SpotInstanceRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/SpotInstanceRequest.html) 对象的列表，可使用这些对象查询 Spot 请求的状态并在其不再处于*打开* 状态后获取其实例 ID。

在 Spot 请求不在处于打开状态后，您可以通过调用其 `SpotInstanceRequest` 方法从 `getInstanceId()` 对象检索其实例 ID。

```
boolean anyOpen; // tracks whether any requests are still open

// a list of instances to tag.
ArrayList<String> instanceIds = new ArrayList<String>();

do {
    DescribeSpotInstanceRequestsRequest describeRequest =
        new DescribeSpotInstanceRequestsRequest();
    describeRequest.setSpotInstanceRequestIds(spotInstanceRequestIds);

    anyOpen=false; // assume no requests are still open

    try {
        // Get the requests to monitor
        DescribeSpotInstanceRequestsResult describeResult =
            ec2.describeSpotInstanceRequests(describeRequest);

        List<SpotInstanceRequest> describeResponses =
            describeResult.getSpotInstanceRequests();

        // are any requests open?
        for (SpotInstanceRequest describeResponse : describeResponses) {
                if (describeResponse.getState().equals("open")) {
                    anyOpen = true;
                    break;
                }
                // get the corresponding instance ID of the spot request
                instanceIds.add(describeResponse.getInstanceId());
        }
    }
    catch (AmazonServiceException e) {
        // Don't break the loop due to an exception (it may be a temporary issue)
        anyOpen = true;
    }

    try {
        Thread.sleep(60*1000); // sleep 60s.
    }
    catch (Exception e) {
        // Do nothing if the thread woke up early.
    }
} while (anyOpen);
```

现在，您可以为返回的实例添加标签：

```
// Create a list of tags to create
ArrayList<Tag> instanceTags = new ArrayList<Tag>();
instanceTags.add(new Tag("keyname1","value1"));

// Create the tag request
CreateTagsRequest createTagsRequest_instances = new CreateTagsRequest();
createTagsRequest_instances.setResources(instanceIds);
createTagsRequest_instances.setTags(instanceTags);

// Tag the instance
try {
    ec2.createTags(createTagsRequest_instances);
}
catch (AmazonServiceException e) {
    // Write out any exceptions that may have occurred.
    System.out.println("Error terminating instances");
    System.out.println("Caught Exception: " + e.getMessage());
    System.out.println("Reponse Status Code: " + e.getStatusCode());
    System.out.println("Error Code: " + e.getErrorCode());
    System.out.println("Request ID: " + e.getRequestId());
}
```

## 取消 Spot 请求并终止实例
<a name="canceling-spot-requests-and-terminating-instances"></a>

### 取消 Spot 请求
<a name="canceling-a-spot-request"></a>

要取消竞价型实例请求，请使用 [CancelSpotInstanceRequestsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CancelSpotInstanceRequestsRequest.html) 对象调用 Amazon EC2 客户端上的 `cancelSpotInstanceRequests`。

```
try {
    CancelSpotInstanceRequestsRequest cancelRequest = new CancelSpotInstanceRequestsRequest(spotInstanceRequestIds);
    ec2.cancelSpotInstanceRequests(cancelRequest);
} catch (AmazonServiceException e) {
    System.out.println("Error cancelling instances");
    System.out.println("Caught Exception: " + e.getMessage());
    System.out.println("Reponse Status Code: " + e.getStatusCode());
    System.out.println("Error Code: " + e.getErrorCode());
    System.out.println("Request ID: " + e.getRequestId());
}
```

### 终止 Spot 实例
<a name="terminating-spot-instances"></a>

您可以通过将任何正在运行的竞价型实例的 ID 传递到 Amazon EC2 客户端的 `terminateInstances()` 方法来终止该实例。

```
try {
    TerminateInstancesRequest terminateRequest = new TerminateInstancesRequest(instanceIds);
    ec2.terminateInstances(terminateRequest);
} catch (AmazonServiceException e) {
    System.out.println("Error terminating instances");
    System.out.println("Caught Exception: " + e.getMessage());
    System.out.println("Reponse Status Code: " + e.getStatusCode());
    System.out.println("Error Code: " + e.getErrorCode());
    System.out.println("Request ID: " + e.getRequestId());
}
```

## 综述
<a name="tutor-spot-adv-bring-together"></a>

综述起来，我们提供一种更加以数据元为导向的方法，将此教程中所示步骤结合到一个易于使用的类别。我们将执行这些操作的一个被称为 `Requests` 的类别实例化。我们还创建了一个 `GettingStartedApp` 类，为我们执行高级函数调用提供主要方法。

可在 [GitHub](https://github.com/aws/aws-sdk-java/tree/master/src/samples/AmazonEC2SpotInstances-Advanced) 查看和下载此示例的完整源代码。

恭喜您！您已经学完了“高级请求功能”教程，了解如何使用适用于 Java 的 AWS SDK 开发 Spot 实例软件。

# 管理 Amazon EC2实例
<a name="examples-ec2-instances"></a>

## 创建实例
<a name="creating-an-instance"></a>

要创建新 Amazon EC2 实例，请调用 AmazonEC2Client 的 `runInstances` 方法，并为它提供 [RunInstancesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RunInstancesRequest.html)，其中包含要使用的[亚马逊机器映像 (AMI)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html) 和一个[实例类型](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html)。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.InstanceType;
import com.amazonaws.services.ec2.model.RunInstancesRequest;
import com.amazonaws.services.ec2.model.RunInstancesResult;
import com.amazonaws.services.ec2.model.Tag;
```

 **代码** 

```
RunInstancesRequest run_request = new RunInstancesRequest()
    .withImageId(ami_id)
    .withInstanceType(InstanceType.T1Micro)
    .withMaxCount(1)
    .withMinCount(1);

RunInstancesResult run_response = ec2.runInstances(run_request);

String reservation_id = run_response.getReservation().getInstances().get(0).getInstanceId();
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/CreateInstance.java)。

## 启动实例
<a name="starting-an-instance"></a>

要启动 Amazon EC2 实例，请调用 AmazonEC2Client 的 `startInstances` 方法，并为它提供 [StartInstancesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/StartInstancesRequest.html)，其中包含要启动实例的 ID。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.StartInstancesRequest;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

StartInstancesRequest request = new StartInstancesRequest()
    .withInstanceIds(instance_id);

ec2.startInstances(request);
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/StartStopInstance.java)。

## 停止实例
<a name="stopping-an-instance"></a>

要停止 Amazon EC2 实例，请调用 AmazonEC2Client 的 `stopInstances` 方法，并为它提供 [StopInstancesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/StopInstancesRequest.html)，其中包含要停止的实例的 ID。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.StopInstancesRequest;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

StopInstancesRequest request = new StopInstancesRequest()
    .withInstanceIds(instance_id);

ec2.stopInstances(request);
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/StartStopInstance.java)。

## 重启实例
<a name="rebooting-an-instance"></a>

要重启 Amazon EC2 实例，请调用 AmazonEC2Client 的 `rebootInstances` 方法，并为它提供 [RebootInstancesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/RebootInstancesRequest.html)，其中包含要重启实例的 ID。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.RebootInstancesRequest;
import com.amazonaws.services.ec2.model.RebootInstancesResult;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

RebootInstancesRequest request = new RebootInstancesRequest()
    .withInstanceIds(instance_id);

RebootInstancesResult response = ec2.rebootInstances(request);
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/RebootInstance.java)。

## 描述实例
<a name="describing-instances"></a>

要列出您的实例，您需要创建 [DescribeInstancesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DescribeInstancesRequest.html) 并调用 AmazonEC2Client 的 `describeInstances` 方法。它将返回 [DescribeInstancesResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DescribeInstancesResult.html) 对象，您可以用它来列出您的账户和区域的 Amazon EC2 实例。

实例按*预留*进行分组。每个预留对应对启动实例的 `startInstances` 的调用。要列出您的实例，您必须首先在每个返回的 `DescribeInstancesResult`Reservation`getReservations' method, and then call `getInstances` 对象上调用 [ 类的 ](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/Reservation.html)。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
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.Reservation;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();
boolean done = false;

DescribeInstancesRequest request = new DescribeInstancesRequest();
while(!done) {
    DescribeInstancesResult response = ec2.describeInstances(request);

    for(Reservation reservation : response.getReservations()) {
        for(Instance instance : reservation.getInstances()) {
            System.out.printf(
                "Found instance with id %s, " +
                "AMI %s, " +
                "type %s, " +
                "state %s " +
                "and monitoring state %s",
                instance.getInstanceId(),
                instance.getImageId(),
                instance.getInstanceType(),
                instance.getState().getName(),
                instance.getMonitoring().getState());
        }
    }

    request.setNextToken(response.getNextToken());

    if(response.getNextToken() == null) {
        done = true;
    }
}
```

结果将分页；您可以获取更多结果，方式是：将从结果对象的 `getNextToken` 方法返回的值传递到您的原始请求对象的 `setNextToken` 方法，然后在下一个 `describeInstances` 调用中使用相同的请求对象。

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/DescribeInstances.java)。

## 监控实例
<a name="monitoring-an-instance"></a>

您可以监控 Amazon EC2 实例的各方面，例如 CPU 和网络利用率、可用内存和剩余磁盘空间。要了解有关实例监控的信息，请参阅《Amazon EC2 用户指南（适用于 Linux 实例）》中的[监控 Amazon EC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring_ec2.html)。

要开始监控实例，您必须用要监控实例的 ID 创建一个 [MonitorInstancesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/MonitorInstancesRequest.html)，并将其传递给 AmazonEC2Client 的 `monitorInstances` 方法。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.MonitorInstancesRequest;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

MonitorInstancesRequest request = new MonitorInstancesRequest()
        .withInstanceIds(instance_id);

ec2.monitorInstances(request);
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/MonitorInstance.java)。

## 停止实例监控
<a name="stopping-instance-monitoring"></a>

要停止监控实例，您必须用要停止监控实例的 ID 创建一个 [UnmonitorInstancesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/UnmonitorInstancesRequest.html)，并将其传递给 AmazonEC2Client 的 `unmonitorInstances` 方法。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.UnmonitorInstancesRequest;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

UnmonitorInstancesRequest request = new UnmonitorInstancesRequest()
    .withInstanceIds(instance_id);

ec2.unmonitorInstances(request);
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/MonitorInstance.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon EC2 API Reference》中的 [RunInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html)
+  《Amazon EC2 API Reference》中的 [DescribeInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html)
+  《Amazon EC2 API Reference》中的 [StartInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StartInstances.html)
+  《Amazon EC2 API Reference》中的 [StopInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_StopInstances.html)
+  《Amazon EC2 API Reference》中的 [RebootInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RebootInstances.html)
+  《Amazon EC2 API Reference》中的 [MonitorInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_MonitorInstances.html)
+  《Amazon EC2 API Reference》中的 [UnmonitorInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_UnmonitorInstances.html)

# 在 Amazon EC2 中使用弹性 IP 地址
<a name="examples-ec2-elastic-ip"></a>

## EC2-Classic 将停用
<a name="retiringEC2Classic"></a>

**警告**  
我们将于 2022 年 8 月 15 日停用 EC2-Classic。我们建议您从 EC2-Classic 迁移到 VPC。有关更多信息，请参阅博客文章 [EC2-Classic-Classic Networking is Retiring – Here's How to Prepare](https://aws.amazon.com/blogs/aws/ec2-classic-is-retiring-heres-how-to-prepare/)。

## 分配弹性 IP 地址
<a name="allocating-an-elastic-ip-address"></a>

要使用弹性 IP 地址，您应首先向您的账户分配这样一个地址，然后将其与您的实例或网络接口关联。

要分配弹性 IP 地址，请使用包含网络类型（经典 EC2 或 VPC）的 [AllocateAddressRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AllocateAddressRequest.html) 对象调用 AmazonEC2Client 的 `allocateAddress` 方法。

返回的 [AllocateAddressResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AllocateAddressResult.html) 包含一个分配 ID，您可以用它来将地址与实例关联，方法是在 [AssociateAddressRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AssociateAddressRequest.html) 中将分配 ID 和实例 ID 传递给 AmazonEC2Client 的 `associateAddress` 方法。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.AllocateAddressRequest;
import com.amazonaws.services.ec2.model.AllocateAddressResult;
import com.amazonaws.services.ec2.model.AssociateAddressRequest;
import com.amazonaws.services.ec2.model.AssociateAddressResult;
import com.amazonaws.services.ec2.model.DomainType;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

AllocateAddressRequest allocate_request = new AllocateAddressRequest()
    .withDomain(DomainType.Vpc);

AllocateAddressResult allocate_response =
    ec2.allocateAddress(allocate_request);

String allocation_id = allocate_response.getAllocationId();

AssociateAddressRequest associate_request =
    new AssociateAddressRequest()
        .withInstanceId(instance_id)
        .withAllocationId(allocation_id);

AssociateAddressResult associate_response =
    ec2.associateAddress(associate_request);
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/AllocateAddress.java)。

## 描述弹性 IP 地址
<a name="describing-elastic-ip-addresses"></a>

要列出分配到您的账户的弹性 IP 地址，请调用 AmazonEC2Client 的 `describeAddresses` 方法。它会返回 [DescribeAddressesResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DescribeAddressesResult.html)，您可以使用它来获取在账户中代表弹性 IP 地址的 [Address](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/Address.html) 对象的列表。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.Address;
import com.amazonaws.services.ec2.model.DescribeAddressesResult;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

DescribeAddressesResult response = ec2.describeAddresses();

for(Address address : response.getAddresses()) {
    System.out.printf(
            "Found address with public IP %s, " +
            "domain %s, " +
            "allocation id %s " +
            "and NIC id %s",
            address.getPublicIp(),
            address.getDomain(),
            address.getAllocationId(),
            address.getNetworkInterfaceId());
}
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/DescribeAddresses.java)。

## 释放弹性 IP 地址
<a name="releasing-an-elastic-ip-address"></a>

要释放弹性 IP 地址，请调用 AmazonEC2Client 的 `releaseAddress` 方法，向其传递 [ReleaseAddressRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/ReleaseAddressRequest.html)，包含您要释放的弹性 IP 地址的分配 ID。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.ReleaseAddressRequest;
import com.amazonaws.services.ec2.model.ReleaseAddressResult;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

ReleaseAddressRequest request = new ReleaseAddressRequest()
    .withAllocationId(alloc_id);

ReleaseAddressResult response = ec2.releaseAddress(request);
```

在释放弹性 IP 地址后，它将回到 AWS IP 地址池，您此后可能不能再使用该地址。请务必更新您的 DNS 记录和通过该地址进行通信的任何服务器或设备。如果您尝试释放已释放的弹性 IP 地址，且该地址已分配到另一个 AWS 账户 账户，您会收到 *AuthFailure* 错误。

如果您使用的是 *EC2-Classic* 或*默认 VPC*，则释放弹性 IP 地址会自动断开该地址与任何实例的关联。要在不释放的情况下取消关联弹性 IP 地址，请使用 AmazonEC2Client 的 `disassociateAddress` 方法。

如果您使用的是非默认 VPC，则*必须*使用 `disassociateAddress` 取消弹性 IP 地址的关联，然后再尝试释放它。否则，Amazon EC2 会返回错误 (*InvalidIPAddress.InUse*)。

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/ReleaseAddress.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon EC2 用户指南（适用于 Linux 实例）》中的[弹性 IP 地址](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html)
+  《Amazon EC2 API Reference》中的 [AllocateAddress](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_AllocateAddress.html)
+  《Amazon EC2 API Reference》中的 [DescribeAddresses](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeAddresses.html)
+  《Amazon EC2 API Reference》中的 [ReleaseAddress](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ReleaseAddress.html)

# 使用区域和可用区
<a name="examples-ec2-regions-zones"></a>

## 描述区域
<a name="describe-regions"></a>

要列出账户可用的区域，请调用 AmazonEC2Client 的 `describeRegions` 方法。该方法返回 [DescribeRegionsResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DescribeRegionsResult.html)。调用返回对象的 `getRegions` 方法，获取表示各个区域的 [Region](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/Region.html) 对象的列表。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.DescribeRegionsResult;
import com.amazonaws.services.ec2.model.Region;
import com.amazonaws.services.ec2.model.AvailabilityZone;
import com.amazonaws.services.ec2.model.DescribeAvailabilityZonesResult;
```

 **代码** 

```
DescribeRegionsResult regions_response = ec2.describeRegions();

for(Region region : regions_response.getRegions()) {
    System.out.printf(
        "Found region %s " +
        "with endpoint %s",
        region.getRegionName(),
        region.getEndpoint());
}
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/DescribeRegionsAndZones.java)。

## 描述可用区
<a name="describe-availability-zones"></a>

要列出账户可用的每个可用区，请调用 AmazonEC2Client 的 `describeAvailabilityZones` 方法。该方法返回 [DescribeAvailabilityZonesResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DescribeAvailabilityZonesResult.html)。调用其 `getAvailabilityZones` 方法，获取表示各个可用区的 [AvailabilityZone](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AvailabilityZone.html) 对象的列表。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.DescribeRegionsResult;
import com.amazonaws.services.ec2.model.Region;
import com.amazonaws.services.ec2.model.AvailabilityZone;
import com.amazonaws.services.ec2.model.DescribeAvailabilityZonesResult;
```

 **代码** 

```
DescribeAvailabilityZonesResult zones_response =
    ec2.describeAvailabilityZones();

for(AvailabilityZone zone : zones_response.getAvailabilityZones()) {
    System.out.printf(
        "Found availability zone %s " +
        "with status %s " +
        "in region %s",
        zone.getZoneName(),
        zone.getState(),
        zone.getRegionName());
}
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/DescribeRegionsAndZones.java)。

## 描述账户
<a name="describe-accounts"></a>

要描述您的账户，请调用 AmazonEC2Client 的 `describeAccountAttributes` 方法。此方法返回 [DescribeAccountAttributesResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DescribeAccountAttributesResult.html) 对象。调用此对象的 `getAccountAttributes` 方法以获取 [AccountAttribute](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AccountAttribute.html) 对象的列表。您可以遍历该列表来检索 [AccountAttribute](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AccountAttribute.html) 对象。

您可以通过调用 [AccountAttribute](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AccountAttribute.html) 对象的 `getAttributeValues` 方法来获取您账户的属性值。此方法返回 [AccountAttributeValue](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AccountAttributeValue.html) 对象的列表。您可以遍历第二个列表来显示属性的值（请参阅以下代码示例）。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.AccountAttributeValue;
import com.amazonaws.services.ec2.model.DescribeAccountAttributesResult;
import com.amazonaws.services.ec2.model.AccountAttribute;
import java.util.List;
import java.util.ListIterator;
```

 **代码** 

```
AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

try{
    DescribeAccountAttributesResult accountResults = ec2.describeAccountAttributes();
    List<AccountAttribute> accountList = accountResults.getAccountAttributes();

    for (ListIterator iter = accountList.listIterator(); iter.hasNext(); ) {

        AccountAttribute attribute = (AccountAttribute) iter.next();
        System.out.print("\n The name of the attribute is "+attribute.getAttributeName());
        List<AccountAttributeValue> values = attribute.getAttributeValues();

         //iterate through the attribute values
        for (ListIterator iterVals = values.listIterator(); iterVals.hasNext(); ) {
            AccountAttributeValue myValue = (AccountAttributeValue) iterVals.next();
            System.out.print("\n The value of the attribute is "+myValue.getAttributeValue());
        }
    }
    System.out.print("Done");
}
catch (Exception e)
{
    e.getStackTrace();
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/DescribeAccount.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon EC2 用户指南（适用于 Linux 实例）》中的[区域和可用区](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html)
+  《Amazon EC2 API Reference》中的 [DescribeRegions](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeRegions.html)
+  《Amazon EC2 API Reference》中的 [DescribeAvailabilityZones](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeAvailabilityZones.html)

# 使用 Amazon EC2 密钥对
<a name="examples-ec2-key-pairs"></a>

## 创建密钥对
<a name="creating-a-key-pair"></a>

要创建密钥对，请使用包含密钥名称的 [CreateKeyPairRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateKeyPairRequest.html) 调用 AmazonEC2Client 的 `createKeyPair` 方法。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.CreateKeyPairRequest;
import com.amazonaws.services.ec2.model.CreateKeyPairResult;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

CreateKeyPairRequest request = new CreateKeyPairRequest()
    .withKeyName(key_name);

CreateKeyPairResult response = ec2.createKeyPair(request);
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/CreateKeyPair.java)。

## 描述密钥对
<a name="describing-key-pairs"></a>

要列出密钥对或获取相关信息，请调用 AmazonEC2Client 的 `describeKeyPairs` 方法。它返回 [DescribeKeyPairsResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DescribeKeyPairsResult.html)，您可以通过调用其 `getKeyPairs` 方法来访问密钥对的列表，该方法返回一个 [KeyPairInfo](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/KeyPairInfo.html) 对象的列表。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.DescribeKeyPairsResult;
import com.amazonaws.services.ec2.model.KeyPairInfo;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

DescribeKeyPairsResult response = ec2.describeKeyPairs();

for(KeyPairInfo key_pair : response.getKeyPairs()) {
    System.out.printf(
        "Found key pair with name %s " +
        "and fingerprint %s",
        key_pair.getKeyName(),
        key_pair.getKeyFingerprint());
}
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/DescribeKeyPairs.java)。

## 删除密钥对
<a name="deleting-a-key-pair"></a>

要删除密钥对，请调用 AmazonEC2Client 的 `deleteKeyPair` 方法，将其传递给一个包含要删除密钥对名称的 [DeleteKeyPairRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DeleteKeyPairRequest.html)。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.DeleteKeyPairRequest;
import com.amazonaws.services.ec2.model.DeleteKeyPairResult;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

DeleteKeyPairRequest request = new DeleteKeyPairRequest()
    .withKeyName(key_name);

DeleteKeyPairResult response = ec2.deleteKeyPair(request);
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/DeleteKeyPair.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon EC2 用户指南（适用于 Linux 实例）》中的 [Amazon EC2 密钥对](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html)
+  《Amazon EC2 API Reference》中的 [CreateKeyPair](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateKeyPair.html)
+  《Amazon EC2 API Reference》中的 [DescribeKeyPairs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeKeyPairs.html)
+  《Amazon EC2 API Reference》中的 [DeleteKeyPair](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteKeyPair.html)

# 在 Amazon EC2 中使用安全组
<a name="examples-ec2-security-groups"></a>

## 正在创建安全组
<a name="creating-a-security-group"></a>

要创建安全组，请使用包含密钥名称的 [CreateSecurityGroupRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/CreateSecurityGroupRequest.html) 调用 AmazonEC2Client 的 `createSecurityGroup` 方法。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest;
import com.amazonaws.services.ec2.model.CreateSecurityGroupResult;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

CreateSecurityGroupRequest create_request = new
    CreateSecurityGroupRequest()
        .withGroupName(group_name)
        .withDescription(group_desc)
        .withVpcId(vpc_id);

CreateSecurityGroupResult create_response =
    ec2.createSecurityGroup(create_request);
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/CreateSecurityGroup.java)。

## 配置安全组
<a name="configuring-a-security-group"></a>

安全组可以控制对 Amazon EC2 实例的入站 (入口) 流量和出站 (出口) 流量。

要向安全组添加入口规则，请使用 AmazonEC2Client 的 `authorizeSecurityGroupIngress` 方法，提供安全组的名称和您想要在 [AuthorizeSecurityGroupIngressRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AuthorizeSecurityGroupIngressRequest.html) 对象中分配给安全组的访问规则 ([IpPermission](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/IpPermission.html))。以下示例演示如何将 IP 权限添加到安全组。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest;
import com.amazonaws.services.ec2.model.CreateSecurityGroupResult;
```

 **代码** 

```
IpRange ip_range = new IpRange()
    .withCidrIp("0.0.0.0/0");

IpPermission ip_perm = new IpPermission()
    .withIpProtocol("tcp")
    .withToPort(80)
    .withFromPort(80)
    .withIpv4Ranges(ip_range);

IpPermission ip_perm2 = new IpPermission()
    .withIpProtocol("tcp")
    .withToPort(22)
    .withFromPort(22)
    .withIpv4Ranges(ip_range);

AuthorizeSecurityGroupIngressRequest auth_request = new
    AuthorizeSecurityGroupIngressRequest()
        .withGroupName(group_name)
        .withIpPermissions(ip_perm, ip_perm2);

AuthorizeSecurityGroupIngressResult auth_response =
    ec2.authorizeSecurityGroupIngress(auth_request);
```

要向安全组添加出口规则，请在 [AuthorizeSecurityGroupEgressRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/AuthorizeSecurityGroupEgressRequest.html) 中向 AmazonEC2Client 的 `authorizeSecurityGroupEgress` 方法提供相似的数据。

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/CreateSecurityGroup.java)。

## 描述安全组
<a name="describing-security-groups"></a>

要描述您的安全组或获取相关信息，请调用 AmazonEC2Client 的 `describeSecurityGroups` 方法。它会返回 [DescribeSecurityGroupsResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DescribeSecurityGroupsResult.html)，您可以通过调用其 `getSecurityGroups` 方法来访问安全组的列表，该方法返回一个 [SecurityGroup](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/ec2/model/SecurityGroup.html) 对象的列表。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest;
import com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult;
```

 **代码** 

```
final String USAGE =
    "To run this example, supply a group id\n" +
    "Ex: DescribeSecurityGroups <group-id>\n";

if (args.length != 1) {
    System.out.println(USAGE);
    System.exit(1);
}

String group_id = args[0];
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/DescribeSecurityGroups.java)。

## 正在删除安全组
<a name="deleting-a-security-group"></a>

要删除安全组，请调用 AmazonEC2Client 的 `deleteSecurityGroup` 方法，将其传递给一个包含要删除安全组 ID 的 [DeleteSecurityGroupRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/ec2/model/DeleteSecurityGroupRequest.html)。

 **导入**。

```
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2ClientBuilder;
import com.amazonaws.services.ec2.model.DeleteSecurityGroupRequest;
import com.amazonaws.services.ec2.model.DeleteSecurityGroupResult;
```

 **代码** 

```
final AmazonEC2 ec2 = AmazonEC2ClientBuilder.defaultClient();

DeleteSecurityGroupRequest request = new DeleteSecurityGroupRequest()
    .withGroupId(group_id);

DeleteSecurityGroupResult response = ec2.deleteSecurityGroup(request);
```

请参阅[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/ec2/src/main/java/aws/example/ec2/DeleteSecurityGroup.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon EC2 用户指南（适用于 Linux 实例）》中的 [Amazon EC2 安全组](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html)
+  《Amazon EC2 用户指南（适用于 Linux 实例）》中的[为您的 Linux 实例授权入站流量](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/authorizing-access-to-an-instance.html)
+  《Amazon EC2 API Reference》中的 [CreateSecurityGroup](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateSecurityGroup.html)
+  《Amazon EC2 API Reference》中的 [DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)
+  《Amazon EC2 API Reference》中的 [DeleteSecurityGroup](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteSecurityGroup.html)
+  《Amazon EC2 API Reference》中的 [AuthorizeSecurityGroupIngress](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_AuthorizeSecurityGroupIngress.html)

# 使用适用于 Java 的 AWS SDK 的 IAM 示例
<a name="examples-iam"></a>

本部分提供使用[适用于 Java 的 AWS SDK](https://aws.amazon.com/sdk-for-java/) 对 [IAM](https://aws.amazon.com/iam/) 进行编程的示例。

 AWS Identity and Access Management (IAM) 使您能够安全地控制您的用户对 AWS 服务和资源的访问权限。使用 IAM，您可以创建和管理 AWS 用户和组，并使用权限来允许和拒绝他们对 AWS 资源的访问。有关 IAM 的完整说明，请访问《[IAM 用户指南](https://docs.aws.amazon.com/IAM/latest/UserGuide/)》。

**注意**  
该示例仅包含演示每种方法所需的代码。[完整的示例代码在 GitHub 上提供](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/java)。您可以从中下载单个源文件，也可以将存储库复制到本地以获得所有示例，然后构建并运行它们。

**Topics**
+ [管理 IAM 访问密钥](examples-iam-access-keys.md)
+ [管理 IAM 用户](examples-iam-users.md)
+ [使用 IAM 账户别名](examples-iam-account-aliases.md)
+ [使用 IAM 策略](examples-iam-policies.md)
+ [使用 IAM 服务器证书](examples-iam-server-certificates.md)

# 管理 IAM 访问密钥
<a name="examples-iam-access-keys"></a>

## 创建访问密钥
<a name="creating-an-access-key"></a>

要创建 IAM 访问密钥，请使用 [CreateAccessKeyRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/CreateAccessKeyRequest.html) 对象调用 AmazonIdentityManagementClient 的 `createAccessKey` 方法。

 `CreateAccessKeyRequest` 有两个构造函数，一个需要用户名，另一个不带参数。如果您使用不带参数的版本，则必须使用 `withUserName` setter 设置用户名，然后再将其传递给 `createAccessKey` 方法。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.CreateAccessKeyRequest;
import com.amazonaws.services.identitymanagement.model.CreateAccessKeyResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

CreateAccessKeyRequest request = new CreateAccessKeyRequest()
    .withUserName(user);

CreateAccessKeyResult response = iam.createAccessKey(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/CreateAccessKey.java)。

## 列出访问密钥
<a name="listing-access-keys"></a>

要列出指定用户的访问密钥，请创建一个 [ListAccessKeysRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/ListAccessKeysRequest.html) 对象，其中包含要列出其密钥的用户名，并将该对象传递给 AmazonIdentityManagementClient 的 `listAccessKeys` 方法。

**注意**  
如果您未向 `listAccessKeys` 提供用户名，则它将尝试列出与签署该请求的 AWS 账户相关联的访问密钥。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.AccessKeyMetadata;
import com.amazonaws.services.identitymanagement.model.ListAccessKeysRequest;
import com.amazonaws.services.identitymanagement.model.ListAccessKeysResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

boolean done = false;
ListAccessKeysRequest request = new ListAccessKeysRequest()
        .withUserName(username);

while (!done) {

    ListAccessKeysResult response = iam.listAccessKeys(request);

    for (AccessKeyMetadata metadata :
            response.getAccessKeyMetadata()) {
        System.out.format("Retrieved access key %s",
                metadata.getAccessKeyId());
    }

    request.setMarker(response.getMarker());

    if (!response.getIsTruncated()) {
        done = true;
    }
}
```

`listAccessKeys` 的结果分页显示 (默认情况下，每个调用最多返回 100 个记录)。您可以调用返回的 [ListAccessKeysResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/ListAccessKeysResult.html) 对象中的 `getIsTruncated`，以查看该查询返回的结果是否少于可用结果。如果是这样，则在 `setMarker` 上调用 `ListAccessKeysRequest` 并将其传递回 `listAccessKeys` 的后续调用。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/ListAccessKeys.java)。

## 检索上次使用访问密钥的时间
<a name="retrieving-an-access-key-s-last-used-time"></a>

要获取上次使用访问密钥的时间，请使用访问密钥 ID（可使用 [GetAccessKeyLastUsedRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/GetAccessKeyLastUsedRequest.html) 对象传入，也可直接传给直接接收访问密钥 ID 的重载）调用 AmazonIdentityManagementClient 的 `getAccessKeyLastUsed` 方法。

然后，您可以使用返回的 [GetAccessKeyLastUsedResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/GetAccessKeyLastUsedResult.html) 对象检索上次使用密钥的时间。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.GetAccessKeyLastUsedRequest;
import com.amazonaws.services.identitymanagement.model.GetAccessKeyLastUsedResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

GetAccessKeyLastUsedRequest request = new GetAccessKeyLastUsedRequest()
    .withAccessKeyId(access_id);

GetAccessKeyLastUsedResult response = iam.getAccessKeyLastUsed(request);

System.out.println("Access key was last used at: " +
        response.getAccessKeyLastUsed().getLastUsedDate());
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/AccessKeyLastUsed.java)。

## 激活或停用访问密钥
<a name="iam-access-keys-update"></a>

您可以激活或停用访问密钥，方式是创建 [UpdateAccessKeyRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/UpdateAccessKeyRequest.html) 对象，提供访问密钥 ID、用户名（可选）和所需[状态](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/StatusType.html)，然后将请求对象传递给 AmazonIdentityManagementClient 的 `updateAccessKey` 方法。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.UpdateAccessKeyRequest;
import com.amazonaws.services.identitymanagement.model.UpdateAccessKeyResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

UpdateAccessKeyRequest request = new UpdateAccessKeyRequest()
    .withAccessKeyId(access_id)
    .withUserName(username)
    .withStatus(status);

UpdateAccessKeyResult response = iam.updateAccessKey(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/UpdateAccessKey.java)。

## 删除访问密钥
<a name="deleting-an-access-key"></a>

要永久删除访问密钥，请调用 AmazonIdentityManagementClient 的 `deleteKey` 方法，并为它提供 [DeleteAccessKeyRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/DeleteAccessKeyRequest.html)，其中包含访问密钥的 ID 和用户名。

**注意**  
密钥在删除后无法再检索或使用。要临时停用密钥，使其可以稍后再次激活，请改用 [updateAccessKey](#iam-access-keys-update) 方法。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.DeleteAccessKeyRequest;
import com.amazonaws.services.identitymanagement.model.DeleteAccessKeyResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

DeleteAccessKeyRequest request = new DeleteAccessKeyRequest()
    .withAccessKeyId(access_key)
    .withUserName(username);

DeleteAccessKeyResult response = iam.deleteAccessKey(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/DeleteAccessKey.java)。

## 更多信息
<a name="more-information"></a>
+  《IAM API Reference》中的 [CreateAccessKey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateAccessKey.html)
+  《IAM API Reference》中的 [ListAccessKeys](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAccessKeys.html)
+  《IAM API Reference》中的 [GetAccessKeyLastUsed](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetAccessKeyLastUsed.html)
+  《IAM API Reference》中的 [UpdateAccessKey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateAccessKey.html)
+  《IAM API Reference》中的 [DeleteAccessKey](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteAccessKey.html)

# 管理 IAM 用户
<a name="examples-iam-users"></a>

## 创建用户
<a name="creating-a-user"></a>

通过向 AmazonIdentityManagementClient 的 `createUser` 方法提供用户名来创建新 IAM 用户，用户名可直接提供，也可以使用包含用户名的 [CreateUserRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/CreateUserRequest.html) 对象。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.CreateUserRequest;
import com.amazonaws.services.identitymanagement.model.CreateUserResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

CreateUserRequest request = new CreateUserRequest()
    .withUserName(username);

CreateUserResult response = iam.createUser(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/CreateUser.java)。

## 列出用户
<a name="listing-users"></a>

要列出您账户中的 IAM 用户，请创建新的 [ListUsersRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/ListUsersRequest.html) 并将其传递给 AmazonIdentityManagementClient 的 `listUsers` 方法。您可以通过在返回的 [ListUsersResult](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/identitymanagement/model/ListUsersResult.html) 对象上调用 `getUsers` 来检索用户列表。

`listUsers` 返回的用户列表已分页。您可以通过调用响应对象的 `getIsTruncated` 方法查看更多可检索的结果。如果返回 `true`，则调用请求对象的 `setMarker()` 方法，并为其传递响应对象的 `getMarker()` 方法的返回值。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.ListUsersRequest;
import com.amazonaws.services.identitymanagement.model.ListUsersResult;
import com.amazonaws.services.identitymanagement.model.User;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

boolean done = false;
ListUsersRequest request = new ListUsersRequest();

while(!done) {
    ListUsersResult response = iam.listUsers(request);

    for(User user : response.getUsers()) {
        System.out.format("Retrieved user %s", user.getUserName());
    }

    request.setMarker(response.getMarker());

    if(!response.getIsTruncated()) {
        done = true;
    }
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/ListUsers.java)。

## 更新用户
<a name="updating-a-user"></a>

要更新用户，请调用 AmazonIdentityManagementClient 对象的 `updateUser` 方法，该方法采用 [UpdateUserRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/UpdateUserRequest.html) 对象，您可以使用它更改用户的*名称* 或*路径*。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.UpdateUserRequest;
import com.amazonaws.services.identitymanagement.model.UpdateUserResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

UpdateUserRequest request = new UpdateUserRequest()
    .withUserName(cur_name)
    .withNewUserName(new_name);

UpdateUserResult response = iam.updateUser(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/UpdateUser.java)。

## 删除用户
<a name="deleting-a-user"></a>

要删除用户，请使用 [UpdateUserRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/UpdateUserRequest.html) 对象调用 AmazonIdentityManagementClient 的 `deleteUser` 请求，该对象中设置了要删除的用户名。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.DeleteConflictException;
import com.amazonaws.services.identitymanagement.model.DeleteUserRequest;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

DeleteUserRequest request = new DeleteUserRequest()
    .withUserName(username);

try {
    iam.deleteUser(request);
} catch (DeleteConflictException e) {
    System.out.println("Unable to delete user. Verify user is not" +
            " associated with any resources");
    throw e;
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/DeleteUser.java)。

## 更多信息
<a name="more-information"></a>
+  《IAM 用户指南》中的 [IAM 用户](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html)
+  《IAM 用户指南》中的[管理 IAM 用户](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_manage.html)
+  《IAM API Reference》中的 [CreateUser](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateUser.html)
+  《IAM API Reference》中的 [ListUsers](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListUsers.html)
+  《IAM API Reference》中的 [UpdateUser](https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateUser.html)
+  《IAM API Reference》中的 [DeleteUser](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteUser.html)

# 使用 IAM 账户别名
<a name="examples-iam-account-aliases"></a>

如果您希望登录页面的 URL 包含贵公司名称（或其他友好标识符）而不是 AWS 账户 ID，则可以为 AWS 账户创建别名。

**注意**  
 AWS 的每个账户支持一个账户别名。

## 创建账户别名
<a name="creating-an-account-alias"></a>

要创建账户别名，请使用包含别名的 [CreateAccountAliasRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/CreateAccountAliasRequest.html) 对象调用 AmazonIdentityManagementClient 的 `createAccountAlias` 方法。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.CreateAccountAliasRequest;
import com.amazonaws.services.identitymanagement.model.CreateAccountAliasResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

CreateAccountAliasRequest request = new CreateAccountAliasRequest()
    .withAccountAlias(alias);

CreateAccountAliasResult response = iam.createAccountAlias(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/CreateAccountAlias.java)。

## 列出账户别名
<a name="listing-account-aliases"></a>

要列出您的账户别名（如果有），请调用 AmazonIdentityManagementClient 的 `listAccountAliases` 方法。

**注意**  
返回的 [ListAccountAliasesResult](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/identitymanagement/model/ListAccountAliasesResult.html) 支持与其他适用于 Java 的 AWS SDK *列出* 方法相同的 `getIsTruncated` 和 `getMarker` 方法，但一个 AWS 账户只能有*一个* 账户别名。

 **导入** 

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.ListAccountAliasesResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

ListAccountAliasesResult response = iam.listAccountAliases();

for (String alias : response.getAccountAliases()) {
    System.out.printf("Retrieved account alias %s", alias);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/ListAccountAliases.java)。

## 删除账户别名
<a name="deleting-an-account-alias"></a>

要删除您账户的别名，请调用 AmazonIdentityManagementClient 的 `deleteAccountAlias` 方法。在删除账户别名时，您必须使用 [DeleteAccountAliasRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/DeleteAccountAliasRequest.html) 对象提供其名称。

 **导入** 

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.DeleteAccountAliasRequest;
import com.amazonaws.services.identitymanagement.model.DeleteAccountAliasResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

DeleteAccountAliasRequest request = new DeleteAccountAliasRequest()
    .withAccountAlias(alias);

DeleteAccountAliasResult response = iam.deleteAccountAlias(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/DeleteAccountAlias.java)。

## 更多信息
<a name="more-information"></a>
+  《IAM 用户指南》中的[您的 AWS 账户 ID 及其别名](https://docs.aws.amazon.com/IAM/latest/UserGuide/console_account-alias.html)
+  《IAM API Reference》中的 [CreateAccountAlias](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateAccountAlias.html)
+  《IAM API Reference》中的 [ListAccountAliases](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAccountAliases.html)
+  《IAM API Reference》中的 [DeleteAccountAlias](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteAccountAlias.html)

# 使用 IAM 策略
<a name="examples-iam-policies"></a>

## 创建策略
<a name="creating-a-policy"></a>

要创建新策略，请在 [CreatePolicyRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/CreatePolicyRequest.html) 中向 AmazonIdentityManagementClient 的 `createPolicy` 方法提供策略名称和 JSON 格式的策略文档。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.CreatePolicyRequest;
import com.amazonaws.services.identitymanagement.model.CreatePolicyResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

CreatePolicyRequest request = new CreatePolicyRequest()
    .withPolicyName(policy_name)
    .withPolicyDocument(POLICY_DOCUMENT);

CreatePolicyResult response = iam.createPolicy(request);
```

IAM policy 文档是使用[明确语法](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_grammar.html)的 JSON 字符串。下面的示例中提供了向 DynamoDB 发出特定请求的访问权。

```
public static final String POLICY_DOCUMENT =
    "{" +
    "  \"Version\": \"2012-10-17\",		 	 	 " +
    "  \"Statement\": [" +
    "    {" +
    "        \"Effect\": \"Allow\"," +
    "        \"Action\": \"logs:CreateLogGroup\"," +
    "        \"Resource\": \"%s\"" +
    "    }," +
    "    {" +
    "        \"Effect\": \"Allow\"," +
    "        \"Action\": [" +
    "            \"dynamodb:DeleteItem\"," +
    "            \"dynamodb:GetItem\"," +
    "            \"dynamodb:PutItem\"," +
    "            \"dynamodb:Scan\"," +
    "            \"dynamodb:UpdateItem\"" +
    "       ]," +
    "       \"Resource\": \"RESOURCE_ARN\"" +
    "    }" +
    "   ]" +
    "}";
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/CreatePolicy.java)。

## 获取策略
<a name="getting-a-policy"></a>

要检索现有策略，请调用 AmazonIdentityManagementClient 的 `getPolicy` 方法，并在 [GetPolicyRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/GetPolicyRequest.html) 对象中提供策略的 ARN。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.GetPolicyRequest;
import com.amazonaws.services.identitymanagement.model.GetPolicyResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

GetPolicyRequest request = new GetPolicyRequest()
    .withPolicyArn(policy_arn);

GetPolicyResult response = iam.getPolicy(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/GetPolicy.java)。

## 附加角色策略
<a name="attaching-a-role-policy"></a>

您可以通过调用 AmazonIdentityManagementClient 的 `attachRolePolicy` 方法，在 [AttachRolePolicyRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/AttachRolePolicyRequest.html) 中向其提供角色名称和策略 ARN 来将策略附加到 IAM 角色 (http://docs.aws.amazon.com/IAM/latest/UserGuide/id\$1roles.html)。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.AttachRolePolicyRequest;
import com.amazonaws.services.identitymanagement.model.AttachedPolicy;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

AttachRolePolicyRequest attach_request =
    new AttachRolePolicyRequest()
        .withRoleName(role_name)
        .withPolicyArn(POLICY_ARN);

iam.attachRolePolicy(attach_request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/AttachRolePolicy.java)。

## 列出附加的角色策略
<a name="listing-attached-role-policies"></a>

通过调用 AmazonIdentityManagementClient 的 `listAttachedRolePolicies` 方法列出角色中附加的策略。这需要 [ListAttachedRolePoliciesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/ListAttachedRolePoliciesRequest.html) 对象，它包含要列出策略的角色名称。

在返回的 [ListAttachedRolePoliciesResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/ListAttachedRolePoliciesResult.html) 对象中调用 `getAttachedPolicies` 来获取所附加策略的列表。如果 `ListAttachedRolePoliciesResult` 对象的 `getIsTruncated` 方法返回 `true`，调用 `ListAttachedRolePoliciesRequest` 对象的 `setMarker` 方法并使用其再次调用 `listAttachedRolePolicies` 来获取下一批结果，则结果可能被截断。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.ListAttachedRolePoliciesRequest;
import com.amazonaws.services.identitymanagement.model.ListAttachedRolePoliciesResult;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

ListAttachedRolePoliciesRequest request =
    new ListAttachedRolePoliciesRequest()
        .withRoleName(role_name);

List<AttachedPolicy> matching_policies = new ArrayList<>();

boolean done = false;

while(!done) {
    ListAttachedRolePoliciesResult response =
        iam.listAttachedRolePolicies(request);

    matching_policies.addAll(
            response.getAttachedPolicies()
                    .stream()
                    .filter(p -> p.getPolicyName().equals(role_name))
                    .collect(Collectors.toList()));

    if(!response.getIsTruncated()) {
        done = true;
    }
    request.setMarker(response.getMarker());
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/AttachRolePolicy.java)。

## 分离角色策略
<a name="detaching-a-role-policy"></a>

要从角色分离策略，请调用 AmazonIdentityManagementClient 的 `detachRolePolicy` 方法，并在 [DetachRolePolicyRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/DetachRolePolicyRequest.html) 中为其提供角色名称和策略 ARN。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.DetachRolePolicyRequest;
import com.amazonaws.services.identitymanagement.model.DetachRolePolicyResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

DetachRolePolicyRequest request = new DetachRolePolicyRequest()
    .withRoleName(role_name)
    .withPolicyArn(policy_arn);

DetachRolePolicyResult response = iam.detachRolePolicy(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/DetachRolePolicy.java)。

## 更多信息
<a name="more-information"></a>
+  《IAM 用户指南》中的 [IAM policy 概述](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html)。
+  《IAM 用户指南》中的 [AWS IAM policy 参考](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies.html)。
+  《IAM API Reference》中的 [CreatePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreatePolicy.html)
+  《IAM API Reference》中的 [GetPolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetPolicy.html)
+  《IAM API Reference》中的 [AttachRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_AttachRolePolicy.html)
+  《IAM API Reference》中的 [ListAttachedRolePolicies](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListAttachedRolePolicies.html)
+  《IAM API Reference》中的 [DetachRolePolicy](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DetachRolePolicy.html)

# 使用 IAM 服务器证书
<a name="examples-iam-server-certificates"></a>

要在 AWS 上启用网站或应用程序的 HTTPS 连接，需要 SSL/TLS *服务器证书*。您可以使用 AWS Certificate Manager 提供的服务器证书或您从外部提供程序获得的服务器证书。

我们建议您使用 ACM 来预置、管理和部署您的服务器证书。利用 ACM，您可以申请证书，将其部署到 AWS 资源，然后让 ACM 为您处理证书续订事宜。ACM 提供的证书是免费的。有关 ACM 的更多信息，请参阅 [ACM 用户指南](https://docs.aws.amazon.com/acm/latest/userguide/)。

## 获取服务器证书
<a name="getting-a-server-certificate"></a>

您可以通过调用 AmazonIdentityManagementClient 的 `getServerCertificate` 方法检索服务器证书，将包含证书名称的 [GetServerCertificateRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/GetServerCertificateRequest.html) 传递给它。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.GetServerCertificateRequest;
import com.amazonaws.services.identitymanagement.model.GetServerCertificateResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

GetServerCertificateRequest request = new GetServerCertificateRequest()
            .withServerCertificateName(cert_name);

GetServerCertificateResult response = iam.getServerCertificate(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/GetServerCertificate.java)。

## 列出服务器证书
<a name="listing-server-certificates"></a>

要列出您的服务器证书，请使用 [ListServerCertificatesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/ListServerCertificatesRequest.html) 调用 AmazonIdentityManagementClient 的 `listServerCertificates` 方法。它返回 [ListServerCertificatesResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/ListServerCertificatesResult.html)。

调用返回的 `ListServerCertificateResult` 对象的 `getServerCertificateMetadataList` 方法获取 [ServerCertificateMetadata](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/ServerCertificateMetadata.html) 对象的列表，您可以用它来获取关于每个证书的信息。

如果 `ListServerCertificateResult` 对象的 `getIsTruncated` 方法返回 `true`，调用 `ListServerCertificatesRequest` 对象的 `setMarker` 方法并使用其再次调用 `listServerCertificates` 来获取下一批结果，则结果可能被截断。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.ListServerCertificatesRequest;
import com.amazonaws.services.identitymanagement.model.ListServerCertificatesResult;
import com.amazonaws.services.identitymanagement.model.ServerCertificateMetadata;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

boolean done = false;
ListServerCertificatesRequest request =
        new ListServerCertificatesRequest();

while(!done) {

    ListServerCertificatesResult response =
        iam.listServerCertificates(request);

    for(ServerCertificateMetadata metadata :
            response.getServerCertificateMetadataList()) {
        System.out.printf("Retrieved server certificate %s",
                metadata.getServerCertificateName());
    }

    request.setMarker(response.getMarker());

    if(!response.getIsTruncated()) {
        done = true;
    }
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/ListServerCertificates.java)。

## 更新服务器证书
<a name="updating-a-server-certificate"></a>

您可以通过调用 AmazonIdentityManagementClient 的 `updateServerCertificate` 方法更新服务器证书的名称或路径。这需要通过服务器证书的当前名称以及要使用的新名称或新路径来设置 [UpdateServerCertificateRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/UpdateServerCertificateRequest.html) 对象。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.UpdateServerCertificateRequest;
import com.amazonaws.services.identitymanagement.model.UpdateServerCertificateResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

UpdateServerCertificateRequest request =
    new UpdateServerCertificateRequest()
        .withServerCertificateName(cur_name)
        .withNewServerCertificateName(new_name);

UpdateServerCertificateResult response =
    iam.updateServerCertificate(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/UpdateServerCertificate.java)。

## 删除服务器证书
<a name="deleting-a-server-certificate"></a>

要删除服务器证书，请使用包含证书名称的 [DeleteServerCertificateRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/identitymanagement/model/DeleteServerCertificateRequest.html) 调用 AmazonIdentityManagementClient 的 `deleteServerCertificate` 方法。

 **导入**。

```
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
import com.amazonaws.services.identitymanagement.model.DeleteServerCertificateRequest;
import com.amazonaws.services.identitymanagement.model.DeleteServerCertificateResult;
```

 **代码** 

```
final AmazonIdentityManagement iam =
    AmazonIdentityManagementClientBuilder.defaultClient();

DeleteServerCertificateRequest request =
    new DeleteServerCertificateRequest()
        .withServerCertificateName(cert_name);

DeleteServerCertificateResult response =
    iam.deleteServerCertificate(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/iam/src/main/java/aws/example/iam/DeleteServerCertificate.java)。

## 更多信息
<a name="more-information"></a>
+  《IAM 用户指南》中的[使用服务器证书](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_server-certs.html)
+  《IAM API Reference》中的 [GetServerCertificate](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetServerCertificate.html)
+  《IAM API Reference》中的 [ListServerCertificates](https://docs.aws.amazon.com/IAM/latest/APIReference/API_ListServerCertificates.html)
+  《IAM API Reference》中的 [UpdateServerCertificate](https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateServerCertificate.html)
+  《IAM API Reference》中的 [DeleteServerCertificate](https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteServerCertificate.html)
+  [ACM 用户指南](https://docs.aws.amazon.com/acm/latest/userguide/) 

# Lambda使用 的 示例适用于 Java 的 AWS SDK
<a name="lambda-examples"></a>

此部分提供使用Lambda 对 适用于 Java 的 AWS SDK 进行编程的示例。

**注意**  
该示例仅包含演示每种方法所需的代码。[完整的示例代码在 GitHub 上提供](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/java)。您可以从中下载单个源文件，也可以将存储库复制到本地以获得所有示例，然后构建并运行它们。

**Topics**
+ [服务操作](examples-lambda.md)

# 调用、列出和删除 Lambda 函数
<a name="examples-lambda"></a>

本部分提供使用适用于 Java 的 AWS SDK 对 Lambda 服务客户端进行编程的示例。要了解如何创建 Lambda 函数，请参阅[如何创建 AWS Lambda 函数](https://docs.aws.amazon.com/toolkit-for-eclipse/v1/user-guide/lambda-tutorial.html)。

**Topics**
+ [调用函数](#invoke-function)
+ [列出函数](#list-function)
+ [删除函数](#delete-function)

## 调用函数
<a name="invoke-function"></a>

可以通过创建 [AWSLambda](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/lambda/AWSLambda.html) 对并调用其 `invoke` 方法来调用 Lambda 函数。创建 [InvokeRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/lambda/model/InvokeRequest.html) 对象可指定其他信息，例如函数名称和要传递给 Lambda 函数的负载。函数名称显示为 *arn:aws:lambda:us-east-1:555556330391:function:HelloFunction*。可以通过查看 AWS 管理控制台中的函数来检索值。

要将负载数据传递给函数，请调用 [InvokeRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/lambda/model/InvokeRequest.html) 对象的 `withPayload` 方法并指定 JSON 格式的字符串，如以下代码示例中所示。

 **导入**。

```
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.lambda.AWSLambda;
import com.amazonaws.services.lambda.AWSLambdaClientBuilder;
import com.amazonaws.services.lambda.model.InvokeRequest;
import com.amazonaws.services.lambda.model.InvokeResult;
import com.amazonaws.services.lambda.model.ServiceException;

import java.nio.charset.StandardCharsets;
```

 **代码** 

以下代码示例演示如何调用 Lambda 函数。

```
        String functionName = args[0];

        InvokeRequest invokeRequest = new InvokeRequest()
                .withFunctionName(functionName)
                .withPayload("{\n" +
                        " \"Hello \": \"Paris\",\n" +
                        " \"countryCode\": \"FR\"\n" +
                        "}");
        InvokeResult invokeResult = null;

        try {
            AWSLambda awsLambda = AWSLambdaClientBuilder.standard()
                    .withCredentials(new ProfileCredentialsProvider())
                    .withRegion(Regions.US_WEST_2).build();

            invokeResult = awsLambda.invoke(invokeRequest);

            String ans = new String(invokeResult.getPayload().array(), StandardCharsets.UTF_8);

            //write out the return value
            System.out.println(ans);

        } catch (ServiceException e) {
            System.out.println(e);
        }

        System.out.println(invokeResult.getStatusCode());
```

请参阅 [Github](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/lambda/src/main/java/com/example/lambda/LambdaInvokeFunction.java) 上的完整示例。

## 列出函数
<a name="list-function"></a>

构建一个 [AWSLambda](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/lambda/AWSLambda.html) 对象并调用其 `listFunctions` 方法。此方法返回一个 [ListFunctionsResult](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/lambda/model/ListFunctionsResult.html) 对象。可以调用此对象的 `getFunctions` 方法来返回 [FunctionConfiguration](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/lambda/model/FunctionConfiguration.html) 对象的列表。可以遍历该列表来检索有关函数的信息。例如，以下 Java 代码示例说明如何获取每个函数名称。

 **导入**。

```
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.lambda.AWSLambda;
import com.amazonaws.services.lambda.AWSLambdaClientBuilder;
import com.amazonaws.services.lambda.model.FunctionConfiguration;
import com.amazonaws.services.lambda.model.ListFunctionsResult;
import com.amazonaws.services.lambda.model.ServiceException;
import java.util.Iterator;
import java.util.List;
```

 **代码** 

以下 Java 代码示例演示如何检索 Lambda 函数名称的列表。

```
        ListFunctionsResult functionResult = null;

        try {
            AWSLambda awsLambda = AWSLambdaClientBuilder.standard()
                    .withCredentials(new ProfileCredentialsProvider())
                    .withRegion(Regions.US_WEST_2).build();

            functionResult = awsLambda.listFunctions();

            List<FunctionConfiguration> list = functionResult.getFunctions();

            for (Iterator iter = list.iterator(); iter.hasNext(); ) {
                FunctionConfiguration config = (FunctionConfiguration)iter.next();

                System.out.println("The function name is "+config.getFunctionName());
            }

        } catch (ServiceException e) {
            System.out.println(e);
        }
```

请参阅 [Github](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/lambda/src/main/java/com/example/lambda/ListFunctions.java) 上的完整示例。

## 删除函数
<a name="delete-function"></a>

构建一个 [AWSLambda](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/lambda/AWSLambda.html) 对象并调用其 `deleteFunction` 方法。创建一个 [DeleteFunctionRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/lambda/model/DeleteFunctionRequest.html) 对象并将该对象传递给 `deleteFunction` 方法。此对象包含要删除的函数的名称等信息。函数名称显示为 *arn:aws:lambda:us-east-1:555556330391:function:HelloFunction*。可以通过查看 AWS 管理控制台中的函数来检索值。

 **导入**。

```
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.lambda.AWSLambda;
import com.amazonaws.services.lambda.AWSLambdaClientBuilder;
import com.amazonaws.services.lambda.model.ServiceException;
import com.amazonaws.services.lambda.model.DeleteFunctionRequest;
```

 **代码** 

以下 Java 代码演示如何删除 Lambda 函数。

```
        String functionName = args[0];
        try {
            AWSLambda awsLambda = AWSLambdaClientBuilder.standard()
                    .withCredentials(new ProfileCredentialsProvider())
                    .withRegion(Regions.US_WEST_2).build();

            DeleteFunctionRequest delFunc = new DeleteFunctionRequest();
            delFunc.withFunctionName(functionName);

            //Delete the function
            awsLambda.deleteFunction(delFunc);
            System.out.println("The function is deleted");

        } catch (ServiceException e) {
            System.out.println(e);
        }
```

请参阅 [Github](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/lambda/src/main/java/com/example/lambda/DeleteFunction.java) 上的完整示例。

# 使用适用于 Java 的 AWS SDK 的 Amazon Pinpoint 示例
<a name="examples-pinpoint"></a>

此部分提供使用[适用于 Java 的 AWS SDK](https://aws.amazon.com/sdk-for-java/) 对 [Amazon Pinpoint](https://aws.amazon.com/pinpoint/) 进行编程的示例。

**注意**  
这些示例仅包含演示每种方法所需的代码。[完整的示例代码在 GitHub 上提供](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/java)。您可以在那里下载单个源文件，也可以将存储库复制到本地以获得所有示例，然后构建并运行这些示例。

**Topics**
+ [在 Amazon Pinpoint 中创建和删除应用程序](examples-pinpoint-create-app.md)
+ [在 Amazon Pinpoint 中创建端点](examples-pinpoint-create-endpoint.md)
+ [在 Amazon Pinpoint 中创建分段](examples-pinpoint-create-segment.md)
+ [在 Amazon Pinpoint 中创建市场活动](examples-pinpoint-create-campaign.md)
+ [在 Amazon Pinpoint 中更新渠道](examples-pinpoint-update-channel.md)

# 在 Amazon Pinpoint 中创建和删除应用程序
<a name="examples-pinpoint-create-app"></a>

应用程序是您在其中为不同应用程序定义受众并通过定制消息吸引此受众的 Amazon Pinpoint 项目。此页中的示例演示如何创建新的应用程序或删除现有应用程序。

## 创建应用程序
<a name="create-an-app"></a>

通过向 [CreateAppRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/CreateAppRequest.html) 对象提供应用程序名称，然后将该对象传递到 AmazonPinpointClient 的 `createApp` 方法，在 Amazon Pinpoint 中创建新的应用程序。

 **导入**。

```
import com.amazonaws.services.pinpoint.AmazonPinpoint;
import com.amazonaws.services.pinpoint.AmazonPinpointClientBuilder;
import com.amazonaws.services.pinpoint.model.CreateAppRequest;
import com.amazonaws.services.pinpoint.model.CreateAppResult;
import com.amazonaws.services.pinpoint.model.CreateApplicationRequest;
```

 **代码** 

```
CreateApplicationRequest appRequest = new CreateApplicationRequest()
		.withName(appName);

CreateAppRequest request = new CreateAppRequest();
request.withCreateApplicationRequest(appRequest);
CreateAppResult result = pinpoint.createApp(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/pinpoint/src/main/java/com/example/pinpoint/CreateApp.java)。

## 删除应用程序
<a name="delete-an-app"></a>

要删除应用程序，请使用 [DeleteAppRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/DeleteAppRequest.html) 对象（其中设置了要删除的应用程序名称）调用 AmazonPinpointClient 的 `deleteApp` 请求。

 **导入**。

```
import com.amazonaws.services.pinpoint.AmazonPinpoint;
import com.amazonaws.services.pinpoint.AmazonPinpointClientBuilder;
```

 **代码** 

```
DeleteAppRequest deleteRequest = new DeleteAppRequest()
		.withApplicationId(appID);

pinpoint.deleteApp(deleteRequest);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/pinpoint/src/main/java/com/example/pinpoint/DeleteApp.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon Pinpoint API Reference》中的 [Apps](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-apps.html)
+  《Amazon Pinpoint API Reference》中的 [App](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-app.html)

# 在 Amazon Pinpoint 中创建端点
<a name="examples-pinpoint-create-endpoint"></a>

终端节点唯一地标识可以使用 Amazon Pinpoint 向其发送推送通知的用户设备。如果您的应用程序启用了 Amazon Pinpoint 支持，则在新用户打开应用程序时，应用程序自动向 Amazon Pinpoint 注册终端节点。以下示例演示如何以编程方式添加新的终端节点。

## 创建端点
<a name="create-an-endpoint"></a>

通过在 Amazon PinpointEndpointRequest[ 对象中提供终端节点数据，在 ](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/EndpointRequest.html) 中创建新的终端节点。

 **导入**。

```
import com.amazonaws.services.pinpoint.AmazonPinpoint;
import com.amazonaws.services.pinpoint.AmazonPinpointClientBuilder;
import com.amazonaws.services.pinpoint.model.UpdateEndpointRequest;
import com.amazonaws.services.pinpoint.model.UpdateEndpointResult;
import com.amazonaws.services.pinpoint.model.EndpointDemographic;
import com.amazonaws.services.pinpoint.model.EndpointLocation;
import com.amazonaws.services.pinpoint.model.EndpointRequest;
import com.amazonaws.services.pinpoint.model.EndpointResponse;
import com.amazonaws.services.pinpoint.model.EndpointUser;
import com.amazonaws.services.pinpoint.model.GetEndpointRequest;
import com.amazonaws.services.pinpoint.model.GetEndpointResult;
```

 **代码** 

```
HashMap<String, List<String>> customAttributes = new HashMap<>();
List<String> favoriteTeams = new ArrayList<>();
favoriteTeams.add("Lakers");
favoriteTeams.add("Warriors");
customAttributes.put("team", favoriteTeams);


EndpointDemographic demographic = new EndpointDemographic()
        .withAppVersion("1.0")
        .withMake("apple")
        .withModel("iPhone")
        .withModelVersion("7")
        .withPlatform("ios")
        .withPlatformVersion("10.1.1")
        .withTimezone("America/Los_Angeles");

EndpointLocation location = new EndpointLocation()
        .withCity("Los Angeles")
        .withCountry("US")
        .withLatitude(34.0)
        .withLongitude(-118.2)
        .withPostalCode("90068")
        .withRegion("CA");

Map<String,Double> metrics = new HashMap<>();
metrics.put("health", 100.00);
metrics.put("luck", 75.00);

EndpointUser user = new EndpointUser()
        .withUserId(UUID.randomUUID().toString());

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); // Quoted "Z" to indicate UTC, no timezone offset
String nowAsISO = df.format(new Date());

EndpointRequest endpointRequest = new EndpointRequest()
        .withAddress(UUID.randomUUID().toString())
        .withAttributes(customAttributes)
        .withChannelType("APNS")
        .withDemographic(demographic)
        .withEffectiveDate(nowAsISO)
        .withLocation(location)
        .withMetrics(metrics)
        .withOptOut("NONE")
        .withRequestId(UUID.randomUUID().toString())
        .withUser(user);
```

然后使用该 EndpointRequest 对象创建 [UpdateEndpointRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/UpdateEndpointRequest.html) 对象。最后，将 UpdateEndpointRequest 对象传递到 AmazonPinpointClient 的 `updateEndpoint` 方法。

 **代码** 

```
UpdateEndpointRequest updateEndpointRequest = new UpdateEndpointRequest()
        .withApplicationId(appId)
        .withEndpointId(endpointId)
        .withEndpointRequest(endpointRequest);

UpdateEndpointResult updateEndpointResponse = client.updateEndpoint(updateEndpointRequest);
System.out.println("Update Endpoint Response: " + updateEndpointResponse.getMessageBody());
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/pinpoint/src/main/java/com/example/pinpoint/CreateEndpoint.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon Pinpoint Developer Guide》中的 [Adding Endpoint](https://docs.aws.amazon.com/pinpoint/latest/developerguide/endpoints.html)
+  《Amazon Pinpoint API Reference》中的 [Endpoint](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-endpoint.html)

# 在 Amazon Pinpoint 中创建分段
<a name="examples-pinpoint-create-segment"></a>

用户分段表示基于共同的特征（例如用户最近什么时候打开了您的应用程序或他们使用哪个设备）的用户子集。以下示例演示如何定义用户分段。

## 创建分段
<a name="create-a-segment"></a>

通过在 Amazon PinpointSegmentDimensions[ 对象中创建分段的维度，在 ](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/SegmentDimensions.html) 中创建新的分段。

 **导入**。

```
import com.amazonaws.services.pinpoint.AmazonPinpoint;
import com.amazonaws.services.pinpoint.AmazonPinpointClientBuilder;
import com.amazonaws.services.pinpoint.model.CreateSegmentRequest;
import com.amazonaws.services.pinpoint.model.CreateSegmentResult;
import com.amazonaws.services.pinpoint.model.AttributeDimension;
import com.amazonaws.services.pinpoint.model.AttributeType;
import com.amazonaws.services.pinpoint.model.RecencyDimension;
import com.amazonaws.services.pinpoint.model.SegmentBehaviors;
import com.amazonaws.services.pinpoint.model.SegmentDemographics;
import com.amazonaws.services.pinpoint.model.SegmentDimensions;
import com.amazonaws.services.pinpoint.model.SegmentLocation;
import com.amazonaws.services.pinpoint.model.SegmentResponse;
import com.amazonaws.services.pinpoint.model.WriteSegmentRequest;
```

 **代码** 

```
Pinpoint pinpoint = AmazonPinpointClientBuilder.standard().withRegion(Regions.US_EAST_1).build();
Map<String, AttributeDimension> segmentAttributes = new HashMap<>();
segmentAttributes.put("Team", new AttributeDimension().withAttributeType(AttributeType.INCLUSIVE).withValues("Lakers"));

SegmentBehaviors segmentBehaviors = new SegmentBehaviors();
SegmentDemographics segmentDemographics = new SegmentDemographics();
SegmentLocation segmentLocation = new SegmentLocation();

RecencyDimension recencyDimension = new RecencyDimension();
recencyDimension.withDuration("DAY_30").withRecencyType("ACTIVE");
segmentBehaviors.setRecency(recencyDimension);

SegmentDimensions dimensions = new SegmentDimensions()
        .withAttributes(segmentAttributes)
        .withBehavior(segmentBehaviors)
        .withDemographic(segmentDemographics)
        .withLocation(segmentLocation);
```

接下来，在 [WriteSegmentRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/SegmentDimensions.html) 中设置 [SegmentDimensions](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/WriteSegmentRequest.html) 对象，接着使用该对象创建 [CreateSegmentRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/CreateSegmentRequest.html) 对象。然后，将 CreateSegmentRequest 对象传递到 AmazonPinpointClient 的 `createSegment` 方法。

 **代码** 

```
WriteSegmentRequest writeSegmentRequest = new WriteSegmentRequest()
        .withName("MySegment").withDimensions(dimensions);

CreateSegmentRequest createSegmentRequest = new CreateSegmentRequest()
        .withApplicationId(appId).withWriteSegmentRequest(writeSegmentRequest);

CreateSegmentResult createSegmentResult = client.createSegment(createSegmentRequest);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/pinpoint/src/main/java/com/example/pinpoint/CreateSegment.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon Pinpoint User Guide》中的 [Amazon Pinpoint Segments](https://docs.aws.amazon.com/pinpoint/latest/userguide/segments.html)
+  《Amazon Pinpoint Developer Guide》中的 [Creating Segments](https://docs.aws.amazon.com/pinpoint/latest/developerguide/segments.html)
+  《Amazon Pinpoint API Reference》中的 [Segments](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-segments.html)
+  《Amazon Pinpoint API Reference》中的 [Segment](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-segment.html)

# 在 Amazon Pinpoint 中创建市场活动
<a name="examples-pinpoint-create-campaign"></a>

您可以使用市场活动来帮助增加应用程序与用户之间的互动。您可以创建市场活动，通过定制消息或特殊促销吸引特定的用户分段。此示例演示如何创建新的标准市场活动，以向特定的分段发送自定义推送消息。

## 创建市场活动
<a name="create-a-campaign"></a>

创建新的市场活动之前，您必须定义[计划](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/Schedule.html)和[消息](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/Message.html)，并在 [WriteCampaignRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/WriteCampaignRequest.html) 对象中设置这些值。

 **导入**。

```
import com.amazonaws.services.pinpoint.AmazonPinpoint;
import com.amazonaws.services.pinpoint.AmazonPinpointClientBuilder;
import com.amazonaws.services.pinpoint.model.CreateCampaignRequest;
import com.amazonaws.services.pinpoint.model.CreateCampaignResult;
import com.amazonaws.services.pinpoint.model.Action;
import com.amazonaws.services.pinpoint.model.CampaignResponse;
import com.amazonaws.services.pinpoint.model.Message;
import com.amazonaws.services.pinpoint.model.MessageConfiguration;
import com.amazonaws.services.pinpoint.model.Schedule;
import com.amazonaws.services.pinpoint.model.WriteCampaignRequest;
```

 **代码** 

```
Schedule schedule = new Schedule()
        .withStartTime("IMMEDIATE");

Message defaultMessage = new Message()
        .withAction(Action.OPEN_APP)
        .withBody("My message body.")
        .withTitle("My message title.");

MessageConfiguration messageConfiguration = new MessageConfiguration()
        .withDefaultMessage(defaultMessage);

WriteCampaignRequest request = new WriteCampaignRequest()
        .withDescription("My description.")
        .withSchedule(schedule)
        .withSegmentId(segmentId)
        .withName("MyCampaign")
        .withMessageConfiguration(messageConfiguration);
```

然后通过将具有市场活动配置的 Amazon PinpointWriteCampaignRequest[ 提供给 ](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/WriteCampaignRequest.html)CreateCampaignRequest[ 对象，在 ](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/pinpoint/model/CreateCampaignRequest.html) 中创建新的市场活动。最后，将 CreateCampaignRequest 对象传递到 AmazonPinpointClient 的 `createCampaign` 方法。

 **代码** 

```
CreateCampaignRequest createCampaignRequest = new CreateCampaignRequest()
        .withApplicationId(appId).withWriteCampaignRequest(request);

CreateCampaignResult result = client.createCampaign(createCampaignRequest);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/pinpoint/src/main/java/com/example/pinpoint/CreateApp.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon Pinpoint User Guide》中的 [Amazon Pinpoint Campaigns](https://docs.aws.amazon.com/pinpoint/latest/userguide/campaigns.html)
+  《Amazon Pinpoint Developer Guide》中的 [Creating Campaigns](https://docs.aws.amazon.com/pinpoint/latest/developerguide/campaigns.html)。
+  《Amazon Pinpoint API Reference》中的 [Campaigns](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-campaigns.html)
+  《Amazon Pinpoint API Reference》中的 [Campaign](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-campaign.html)
+  《Amazon Pinpoint API Reference》中的 [Campaign Activities](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-campaign-activities.html)
+  《Amazon Pinpoint API Reference》中的 [Campaign Versions](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-campaign-versions.html)
+  《Amazon Pinpoint API Reference》中的 [Campaign Version](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-campaign-version.html)

# 在 Amazon Pinpoint 中更新渠道
<a name="examples-pinpoint-update-channel"></a>

渠道定义您可将消息传递到的平台类型。此示例演示如何使用 APN 渠道发送消息。

## 更新渠道
<a name="update-a-channel"></a>

通过提供应用程序 ID 以及您希望更新的渠道类型的请求对象，在 Amazon Pinpoint 中启用渠道。此示例将更新 APN 渠道，这需要 [APNSChannelRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/APNSChannelRequest.html) 对象。请在 [UpdateApnsChannelRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/pinpoint/model/UpdateApnsChannelRequest.html) 中进行设置并将该对象传递到 AmazonPinpointClient 的 `updateApnsChannel` 方法。

 **导入**。

```
import com.amazonaws.services.pinpoint.AmazonPinpoint;
import com.amazonaws.services.pinpoint.AmazonPinpointClientBuilder;
import com.amazonaws.services.pinpoint.model.APNSChannelRequest;
import com.amazonaws.services.pinpoint.model.APNSChannelResponse;
import com.amazonaws.services.pinpoint.model.GetApnsChannelRequest;
import com.amazonaws.services.pinpoint.model.GetApnsChannelResult;
import com.amazonaws.services.pinpoint.model.UpdateApnsChannelRequest;
import com.amazonaws.services.pinpoint.model.UpdateApnsChannelResult;
```

 **代码** 

```
APNSChannelRequest request = new APNSChannelRequest()
		.withEnabled(enabled);

UpdateApnsChannelRequest updateRequest = new UpdateApnsChannelRequest()
		.withAPNSChannelRequest(request)
		.withApplicationId(appId);
UpdateApnsChannelResult result = client.updateApnsChannel(updateRequest);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/pinpoint/src/main/java/com/example/pinpoint/UpdateChannel.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon Pinpoint User Guide》中的 [Amazon Pinpoint Channels](https://docs.aws.amazon.com/pinpoint/latest/userguide/channels.html)
+  《Amazon Pinpoint API Reference》中的 [ADM Channel](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-adm-channel.html)
+  《Amazon Pinpoint API Reference》中的 [APNs Channel](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-apns-channel.html)
+  《Amazon Pinpoint API Reference》中的 [APNs Sandbox Channel](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-apns-sandbox-channel.html)
+  《Amazon Pinpoint API Reference》中的 [APNs VoIP Channel](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-apns-voip-channel.html)
+  《Amazon Pinpoint API Reference》中的 [APNs VoIP Sandbox Channel](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-apns-voip-sandbox-channel.html)
+  《Amazon Pinpoint API Reference》中的 [Baidu Channel](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-baidu-channel.html)
+  《Amazon Pinpoint API Reference》中的 [Email Channel](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-email-channel.html)
+  《Amazon Pinpoint API Reference》中的 [GCM Channel](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-gcm-channel.html)
+  《Amazon Pinpoint API Reference》中的 [SMS Channel](https://docs.aws.amazon.com/pinpoint/latest/apireference/rest-api-sms-channel.html)

# 使用适用于 Java 的 AWS SDK 的 Amazon S3 示例
<a name="examples-s3"></a>

此部分提供使用[适用于 Java 的 AWS SDK](https://aws.amazon.com/sdk-for-java/) 对 [Amazon S3](https://aws.amazon.com/s3/) 进行编程的示例。

**注意**  
这些示例仅包含演示每种方法所需的代码。[完整的示例代码在 GitHub 上提供](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/java)。您可以在那里下载单个源文件，也可以将存储库复制到本地以获得所有示例，然后构建并运行这些示例。

**Topics**
+ [创建、列出和删除 Amazon S3 桶](examples-s3-buckets.md)
+ [在 Amazon S3 对象上执行操作](examples-s3-objects.md)
+ [管理对桶和对象的 Amazon S3 访问权限](examples-s3-access-permissions.md)
+ [使用桶策略管理对 Amazon S3 桶的访问](examples-s3-bucket-policies.md)
+ [使用 TransferManager 执行 Amazon S3 操作](examples-s3-transfermanager.md)
+ [将 Amazon S3 桶配置为网站](examples-s3-website-configuration.md)
+ [使用 Amazon S3 客户端加密](examples-crypto.md)

# 创建、列出和删除 Amazon S3 桶
<a name="examples-s3-buckets"></a>

Amazon S3 中的每个对象（文件）必须放入*存储桶*，它代表对象的集合（容器）。每个存储桶使用必须唯一的*键* (名称) 命名。有关桶及其配置的详细信息，请参阅《Amazon Simple Storage Service 用户指南》中的[使用 Amazon S3 桶](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html)。

**注意**  
最佳实践  
建议您对 [ 存储桶启用 ](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html)AbortIncompleteMultipartUploadAmazon S3 生命周期规则。  
该规则指示 Amazon S3 中止在启动后没有在指定天数内完成的分段上传。当超过设置的时间限制时，Amazon S3 将中止上传，然后删除未完成的上传数据。  
有关更多信息，请参阅《Amazon S3 用户指南》中的[使用版本控制的桶生命周期配置](https://docs.aws.amazon.com/AmazonS3/latest/userguide/lifecycle-configuration-bucket-with-versioning.html)。

**注意**  
这些代码示例假定您了解[使用适用于 Java 的 AWS SDK](basics.md) 中的内容，并且已使用[设置用于开发的 AWS 凭证和区域](setup-credentials.md)中的信息配置默认 AWS 凭证。

## 创建存储桶
<a name="create-bucket"></a>

使用 AmazonS3 客户端的 `createBucket` 方法。会返回新的[存储桶](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/Bucket.html)。如果存储桶已存在，`createBucket` 方法将引发异常。

**注意**  
要尝试创建一个具有相同名称的存储桶来检查存储桶是否已存在，请调用 `doesBucketExist` 方法。如果存储桶存在，它将返回 `true`，否则将返回 `false`。

 **导入**。

```
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.Bucket;

import java.util.List;
```

 **代码** 

```
if (s3.doesBucketExistV2(bucket_name)) {
    System.out.format("Bucket %s already exists.\n", bucket_name);
    b = getBucket(bucket_name);
} else {
    try {
        b = s3.createBucket(bucket_name);
    } catch (AmazonS3Exception e) {
        System.err.println(e.getErrorMessage());
    }
}
return b;
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/CreateBucket.java)。

## 列出存储桶
<a name="list-buckets"></a>

使用 AmazonS3 客户端的 `listBucket` 方法。如果成功，会返回[存储桶](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/Bucket.html)的列表。

 **导入**。

```
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.Bucket;

import java.util.List;
```

 **代码** 

```
List<Bucket> buckets = s3.listBuckets();
System.out.println("Your {S3} buckets are:");
for (Bucket b : buckets) {
    System.out.println("* " + b.getName());
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/ListBuckets.java)。

## 删除存储桶
<a name="delete-bucket"></a>

在删除 Amazon S3 存储桶前，必须先确保存储桶为空，否则会导致错误。如果您的[存储桶受版本控制](https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html)，则必须同时删除与该存储桶关联的所有受版本控制对象。

**注意**  
[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/DeleteBucket.java)中依次包含上述每个步骤，提供用于删除 Amazon S3 存储桶及其内容的完整解决方案。

**Topics**
+ [删除不受版本控制的存储桶之前先删除其中的对象](#remove-objects-from-an-unversioned-bucket-before-deleting-it)
+ [删除受版本控制的存储桶之前先删除其中的对象](#remove-objects-from-a-versioned-bucket-before-deleting-it)
+ [删除空存储桶](#delete-an-empty-bucket)

### 删除不受版本控制的存储桶之前先删除其中的对象
<a name="remove-objects-from-an-unversioned-bucket-before-deleting-it"></a>

使用 AmazonS3 客户端的 `listObjects` 方法来检索对象列表，并使用 `deleteObject` 删除每个对象。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;

import java.util.Iterator;
```

 **代码** 

```
System.out.println(" - removing objects from bucket");
ObjectListing object_listing = s3.listObjects(bucket_name);
while (true) {
    for (Iterator<?> iterator =
         object_listing.getObjectSummaries().iterator();
         iterator.hasNext(); ) {
        S3ObjectSummary summary = (S3ObjectSummary) iterator.next();
        s3.deleteObject(bucket_name, summary.getKey());
    }

    // more object_listing to retrieve?
    if (object_listing.isTruncated()) {
        object_listing = s3.listNextBatchOfObjects(object_listing);
    } else {
        break;
    }
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/DeleteBucket.java)。

### 删除受版本控制的存储桶之前先删除其中的对象
<a name="remove-objects-from-a-versioned-bucket-before-deleting-it"></a>

如果您使用[受版本控制的存储桶](https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html)，还需要先删除存储桶中存储的所有受版本控制对象，然后才能删除存储桶。

使用在删除桶中的对象时所用的类似方法，通过使用 AmazonS3 客户端的 `listVersions` 方法列出所有受版本控制的对象，然后使用 `deleteVersion` 删除各个对象。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;

import java.util.Iterator;
```

 **代码** 

```
System.out.println(" - removing versions from bucket");
VersionListing version_listing = s3.listVersions(
        new ListVersionsRequest().withBucketName(bucket_name));
while (true) {
    for (Iterator<?> iterator =
         version_listing.getVersionSummaries().iterator();
         iterator.hasNext(); ) {
        S3VersionSummary vs = (S3VersionSummary) iterator.next();
        s3.deleteVersion(
                bucket_name, vs.getKey(), vs.getVersionId());
    }

    if (version_listing.isTruncated()) {
        version_listing = s3.listNextBatchOfVersions(
                version_listing);
    } else {
        break;
    }
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/DeleteBucket.java)。

### 删除空存储桶
<a name="delete-an-empty-bucket"></a>

在删除桶中的对象（包括所有受版本控制的对象）后，就可以使用 AmazonS3 客户端的 `deleteBucket` 方法删除桶本身。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;

import java.util.Iterator;
```

 **代码** 

```
System.out.println(" OK, bucket ready to delete!");
s3.deleteBucket(bucket_name);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/DeleteBucket.java)。

# 在 Amazon S3 对象上执行操作
<a name="examples-s3-objects"></a>

Amazon S3 对象表示一个*文件* 或数据集合。每个对象必须驻留在一个[存储桶](examples-s3-buckets.md)中。

**注意**  
这些代码示例假定您了解[使用适用于 Java 的 AWS SDK](basics.md) 中的内容，并且已使用[设置用于开发的 AWS 凭证和区域](setup-credentials.md)中的信息配置默认 AWS 凭证。

**Topics**
+ [上传对象](#upload-object)
+ [列出对象](#list-objects)
+ [下载对象](#download-object)
+ [复制、移动或重命名对象](#copy-object)
+ [删除对象](#delete-object)
+ [一次性删除多个对象](#delete-objects)

## 上传对象
<a name="upload-object"></a>

使用 AmazonS3 客户端的 `putObject` 方法，并为其提供桶名称、键名称和要上传的文件。*存储桶必须存在，否则将出现错误*。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
```

 **代码** 

```
System.out.format("Uploading %s to S3 bucket %s...\n", file_path, bucket_name);
final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
try {
    s3.putObject(bucket_name, key_name, new File(file_path));
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/PutObject.java)。

## 列出对象
<a name="list-objects"></a>

要获取桶中的对象列表，请使用 AmazonS3 客户端的 `listObjects` 方法，并为其提供桶名称。

`listObjects` 方法返回一个 [ObjectListing](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/ObjectListing.html) 对象，该对象提供有关存储桶中对象的信息。要列出对象名称（键），可使用 `getObjectSummaries` 方法获取 [S3ObjectSummary](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/S3ObjectSummary.html) 对象的列表，其中每个对象均表示存储桶中的一个对象。然后调用其 `getKey` 方法以检索对象名称。

 **导入**。

```
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ListObjectsV2Result;
import com.amazonaws.services.s3.model.S3ObjectSummary;
```

 **代码** 

```
System.out.format("Objects in S3 bucket %s:\n", bucket_name);
final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
ListObjectsV2Result result = s3.listObjectsV2(bucket_name);
List<S3ObjectSummary> objects = result.getObjectSummaries();
for (S3ObjectSummary os : objects) {
    System.out.println("* " + os.getKey());
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/ListObjects.java)。

## 下载对象
<a name="download-object"></a>

使用 AmazonS3 客户端的 `getObject` 方法，并向其传递要下载的桶和对象的名称。如果成功，此方法将返回一个 [S3Object](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/S3Object.html)。*指定的存储桶和对象键必须存在，否则将出现错误*。

您可以通过对 `getObjectContent` 调用 `S3Object` 来获取对象的内容。这将返回一个 [S3ObjectInputStream](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/S3ObjectInputStream.html)，其行为与标准 Java `InputStream` 对象的相同。

以下示例从 S3 下载一个对象，然后将该对象的内容保存到一个文件（使用与对象键相同的名称）：

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;

import java.io.File;
```

 **代码** 

```
System.out.format("Downloading %s from S3 bucket %s...\n", key_name, bucket_name);
final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
try {
    S3Object o = s3.getObject(bucket_name, key_name);
    S3ObjectInputStream s3is = o.getObjectContent();
    FileOutputStream fos = new FileOutputStream(new File(key_name));
    byte[] read_buf = new byte[1024];
    int read_len = 0;
    while ((read_len = s3is.read(read_buf)) > 0) {
        fos.write(read_buf, 0, read_len);
    }
    s3is.close();
    fos.close();
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
} catch (FileNotFoundException e) {
    System.err.println(e.getMessage());
    System.exit(1);
} catch (IOException e) {
    System.err.println(e.getMessage());
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/GetObject.java)。

## 复制、移动或重命名对象
<a name="copy-object"></a>

您可以使用 AmazonS3 客户端的 `copyObject` 方法将对象从一个桶复制到另一个桶。它采用要从中复制的存储桶的名称、要复制的对象以及目标存储桶名称。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
```

 **代码** 

```
try {
    s3.copyObject(from_bucket, object_key, to_bucket, object_key);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
System.out.println("Done!");
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/CopyObject.java)。

**注意**  
您可以将 `copyObject` 与 [deleteObject](#delete-object) 配合使用来**移动**或**重命名**对象，方式是先将对象复制到新名称（您可以使用与源和目标相同的存储桶），然后从对象的旧位置删除对象。

## 删除对象
<a name="delete-object"></a>

使用 AmazonS3 客户端的 `deleteObject` 方法，并向其传递要删除的桶和对象的名称。*指定的存储桶和对象键必须存在，否则将出现错误*。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
```

 **代码** 

```
final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
try {
    s3.deleteObject(bucket_name, object_key);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/DeleteObject.java)。

## 一次性删除多个对象
<a name="delete-objects"></a>

使用 AmazonS3 客户端 `deleteObjects` 的方法，您可以将同一个桶中的多个对象的名称传递给 link:sdk-for-java/v1/reference/com/amazonaws/services/s3/model/DeleteObjectsRequest.html`` 方法，从而删除这些对象。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
```

 **代码** 

```
final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
try {
    DeleteObjectsRequest dor = new DeleteObjectsRequest(bucket_name)
            .withKeys(object_keys);
    s3.deleteObjects(dor);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/DeleteObjects.java)。

# 管理对桶和对象的 Amazon S3 访问权限
<a name="examples-s3-access-permissions"></a>

您可以为 Amazon S3 存储桶和对象使用访问控制列表 (ACL)，以实现对 Amazon S3 资源的精细控制。

**注意**  
这些代码示例假定您了解[使用适用于 Java 的 AWS SDK](basics.md) 中的内容，并且已使用[设置用于开发的 AWS 凭证和区域](setup-credentials.md)中的信息配置默认 AWS 凭证。

## 获取存储桶的访问控制列表
<a name="get-the-access-control-list-for-a-bucket"></a>

要获取桶的当前 ACL，请调用 AmazonS3 的 `getBucketAcl` 方法，将*桶名称* 传递给它以进行查询。此方法将返回 [AccessControlList](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/AccessControlList.html) 对象。要获取列表中的每个访问授权，请调用其 `getGrantsAsList` 方法，这会返回一个包含 [Grant](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/Grant.html) 对象的标准 Java 列表。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.Grant;
```

 **代码** 

```
final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
try {
    AccessControlList acl = s3.getBucketAcl(bucket_name);
    List<Grant> grants = acl.getGrantsAsList();
    for (Grant grant : grants) {
        System.out.format("  %s: %s\n", grant.getGrantee().getIdentifier(),
                grant.getPermission().toString());
    }
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/GetAcl.java)。

## 设置存储桶的访问控制列表
<a name="set-the-access-control-list-for-a-bucket"></a>

要添加或修改存储桶对 ACL 的权限，请调用 AmazonS3 的 `setBucketAcl` 方法。这需要一个 [AccessControlList](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/AccessControlList.html) 对象，它包含被授权者和要设置的访问级别的列表。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.EmailAddressGrantee;
```

 **代码** 

```
final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
try {
    // get the current ACL
    AccessControlList acl = s3.getBucketAcl(bucket_name);
    // set access for the grantee
    EmailAddressGrantee grantee = new EmailAddressGrantee(email);
    Permission permission = Permission.valueOf(access);
    acl.grantPermission(grantee, permission);
    s3.setBucketAcl(bucket_name, acl);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

**注意**  
您可以使用 [Grantee](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/Grantee.html) 类直接提供被授权者的唯一标识符，也可以使用 [EmailAddressGrantee](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/EmailAddressGrantee.html) 类通过电子邮件设置被授权者，这里采用后者。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/SetAcl.java)。

## 获取对象的访问控制列表
<a name="get-the-access-control-list-for-an-object"></a>

要获取对象的当前 ACL，请调用 AmazonS3 的 `getObjectAcl` 方法，将*桶名称* 和*对象名称* 传递给它以进行查询。和 `getBucketAcl` 类似，此方法将返回一个 [AccessControlList](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/AccessControlList.html) 对象，您可以用它来检查每个 [Grant](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/Grant.html)。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.Grant;
```

 **代码** 

```
try {
    AccessControlList acl = s3.getObjectAcl(bucket_name, object_key);
    List<Grant> grants = acl.getGrantsAsList();
    for (Grant grant : grants) {
        System.out.format("  %s: %s\n", grant.getGrantee().getIdentifier(),
                grant.getPermission().toString());
    }
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/GetAcl.java)。

## 设置对象的访问控制列表
<a name="set-the-access-control-list-for-an-object"></a>

要添加或修改对象对 ACL 的权限，请调用 AmazonS3 的 `setObjectAcl` 方法。这需要一个 [AccessControlList](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/AccessControlList.html) 对象，它包含被授权者和要设置的访问级别的列表。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.EmailAddressGrantee;
```

 **代码** 

```
    try {
        // get the current ACL
        AccessControlList acl = s3.getObjectAcl(bucket_name, object_key);
        // set access for the grantee
        EmailAddressGrantee grantee = new EmailAddressGrantee(email);
        Permission permission = Permission.valueOf(access);
        acl.grantPermission(grantee, permission);
        s3.setObjectAcl(bucket_name, object_key, acl);
    } catch (AmazonServiceException e) {
        System.err.println(e.getErrorMessage());
        System.exit(1);
    }
}
```

**注意**  
您可以使用 [Grantee](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/Grantee.html) 类直接提供被授权者的唯一标识符，也可以使用 [EmailAddressGrantee](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/EmailAddressGrantee.html) 类通过电子邮件设置被授权者，这里采用后者。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/SetAcl.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon S3 API Reference》中的 [GET Bucket acl](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETacl.html)
+  《Amazon S3 API Reference》中的 [PUT Bucket acl](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTacl.html)
+  《Amazon S3 API Reference》中的 [GET Object acl](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGETacl.html)
+  《Amazon S3 API Reference》中的 [PUT Object acl](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUTacl.html)

# 使用桶策略管理对 Amazon S3 桶的访问
<a name="examples-s3-bucket-policies"></a>

您可以设置、获取或删除*存储桶策略* 来管理对 Amazon S3 存储桶的访问。

## 设置存储桶策略
<a name="set-s3-bucket-policy"></a>

您可以通过以下方式为特定的 S3 存储桶设置存储桶策略：
+ 调用 AmazonS3 客户端的 `setBucketPolicy` 并为其提供 [SetBucketPolicyRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/SetBucketPolicyRequest.html) 
+ 使用接收存储桶名称和策略文本 (JSON 格式) 的 `setBucketPolicy` 重载直接设置策略

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.policy.Policy;
import com.amazonaws.auth.policy.Principal;
```

 **代码** 

```
    s3.setBucketPolicy(bucket_name, policy_text);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

### 使用策略类生成或验证策略
<a name="use-s3-bucket-policy-class"></a>

为 `setBucketPolicy` 提供存储桶策略时，您可以执行以下操作：
+ 使用 JSON 格式的文本字符串直接指定策略
+ 使用 [Policy](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/auth/policy/Policy.html) 类构建策略

使用 `Policy` 类，您不必担心如何正确设置文本字符串的格式。要从 `Policy` 类获取 JSON 策略文本，请使用其 `toJson` 方法。

 **导入**。

```
import com.amazonaws.auth.policy.Resource;
import com.amazonaws.auth.policy.Statement;
import com.amazonaws.auth.policy.actions.S3Actions;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
```

 **代码** 

```
        new Statement(Statement.Effect.Allow)
                .withPrincipals(Principal.AllUsers)
                .withActions(S3Actions.GetObject)
                .withResources(new Resource(
                        "{region-arn}s3:::" + bucket_name + "/*")));
return bucket_policy.toJson();
```

`Policy` 类还提供 `fromJson` 方法，它会尝试使用传入的 JSON 字符串构建策略。该方法会验证文本以确保可以转换为有效策略结构，如果策略文本无效，就会失败并引发 `IllegalArgumentException`。

```
Policy bucket_policy = null;
try {
    bucket_policy = Policy.fromJson(file_text.toString());
} catch (IllegalArgumentException e) {
    System.out.format("Invalid policy text in file: \"%s\"",
            policy_file);
    System.out.println(e.getMessage());
}
```

您可以使用此方法，提前验证您从文件读入或通过其他方法得到的策略。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/SetBucketPolicy.java)。

## 获取存储桶策略
<a name="get-s3-bucket-policy"></a>

要检索 Amazon S3 桶的策略，请调用 AmazonS3 客户端的 `getBucketPolicy` 方法，将桶名称传递给它以获取策略。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
```

 **代码** 

```
  try {
      BucketPolicy bucket_policy = s3.getBucketPolicy(bucket_name);
      policy_text = bucket_policy.getPolicyText();
  } catch (AmazonServiceException e) {
      System.err.println(e.getErrorMessage());
      System.exit(1);
  }
```

如果指定的存储桶不存在、您没有访问该存储桶的权限或者其中不包含存储桶策略，会引发 `AmazonServiceException`。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/GetBucketPolicy.java)。

## 删除存储桶策略
<a name="delete-s3-bucket-policy"></a>

要删除桶策略，请调用 AmazonS3 客户端的 `deleteBucketPolicy`，并为其提供桶名称。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
```

 **代码** 

```
  try {
      s3.deleteBucketPolicy(bucket_name);
  } catch (AmazonServiceException e) {
      System.err.println(e.getErrorMessage());
      System.exit(1);
  }
```

即使存储桶中还没有策略，该方法也会成功。如果您指定的存储桶名称不存在，或者您没有访问该存储桶的权限，会引发 `AmazonServiceException`。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/DeleteBucketPolicy.java)。

## 更多信息
<a name="more-info"></a>
+  《Amazon Simple Storage Service 用户指南》中的[访问策略语言概述](https://docs.aws.amazon.com/AmazonS3/latest/dev/access-policy-language-overview.html)
+  《Amazon Simple Storage Service 用户指南》中的[桶策略示例](https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html)

# 使用 TransferManager 执行 Amazon S3 操作
<a name="examples-s3-transfermanager"></a>

您可以使用适用于 Java 的 AWS SDK TransferManager 类可靠地将文件从本地环境传输到 Amazon S3 并将对象从一个 S3 位置复制到另一个 S3 位置。`TransferManager` 可获取传输进度，以及暂停或恢复上传和下载。

**注意**  
最佳实践  
建议您对 [ 存储桶启用 ](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html)AbortIncompleteMultipartUploadAmazon S3 生命周期规则。  
该规则指示 Amazon S3 中止在启动后没有在指定天数内完成的分段上传。当超过设置的时间限制时，Amazon S3 将中止上传，然后删除未完成的上传数据。  
有关更多信息，请参阅《Amazon S3 用户指南》中的[使用版本控制的桶生命周期配置](https://docs.aws.amazon.com/AmazonS3/latest/userguide/lifecycle-configuration-bucket-with-versioning.html)。

**注意**  
这些代码示例假定您了解[使用适用于 Java 的 AWS SDK](basics.md) 中的内容，并且已使用[设置用于开发的 AWS 凭证和区域](setup-credentials.md)中的信息配置默认 AWS 凭证。

## 上传文件和目录
<a name="transfermanager-uploading"></a>

TransferManager 可将文件、文件列表和目录上传到您[之前创建](examples-s3-buckets.md#create-bucket)的任何 Amazon S3 桶。

**Topics**
+ [上传单个文件](#transfermanager-upload-file)
+ [上传文件列表](#transfermanager-upload-file-list)
+ [上传目录](#transfermanager-upload-directory)

### 上传单个文件
<a name="transfermanager-upload-file"></a>

调用 TransferManager 的 `upload` 方法，提供 Amazon S3 桶名称、键（对象）名称和代表要上传的文件的标准 Java [File](https://docs.oracle.com/javase/8/docs/api/index.html?java/io/File.html) 对象。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.transfer.MultipleFileUpload;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.TransferManagerBuilder;
import com.amazonaws.services.s3.transfer.Upload;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
```

 **代码** 

```
File f = new File(file_path);
TransferManager xfer_mgr = TransferManagerBuilder.standard().build();
try {
    Upload xfer = xfer_mgr.upload(bucket_name, key_name, f);
    // loop with Transfer.isDone()
    XferMgrProgress.showTransferProgress(xfer);
    //  or block with Transfer.waitForCompletion()
    XferMgrProgress.waitForCompletion(xfer);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
xfer_mgr.shutdownNow();
```

`upload` 方法*立即*返回值，为您提供一个 `Upload` 对象，用于检查传输状态或等待传输完成。

请参阅[等待传输完成](#transfermanager-wait-for-completion)以了解有关在调用 TransferManager 的 `shutdownNow` 方法之前使用 `waitForCompletion` 成功完成传输的信息。在等待传输完成时，您可以轮询或侦听有关其状态和进度的更新。有关更多信息，请参阅[获取传输状态和进度](#transfermanager-get-status-and-progress)。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/XferMgrUpload.java)。

### 上传文件列表
<a name="transfermanager-upload-file-list"></a>

要通过一次操作上传多个文件，请调用 TransferManager `uploadFileList` 方法，并为其提供：
+ Amazon S3 存储桶名称
+ 一个*键前缀*，它将添加到创建的对象名称的前面 (将对象放置到的存储桶中的路径)
+ 一个 [File](https://docs.oracle.com/javase/8/docs/api/index.html?java/io/File.html) 对象，此对象表示将从中创建文件路径的相对目录
+ 一个 [List](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/List.html) 对象，包含一组要上传的 [File](https://docs.oracle.com/javase/8/docs/api/index.html?java/io/File.html) 对象

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.transfer.MultipleFileUpload;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.TransferManagerBuilder;
import com.amazonaws.services.s3.transfer.Upload;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
```

 **代码** 

```
ArrayList<File> files = new ArrayList<File>();
for (String path : file_paths) {
    files.add(new File(path));
}

TransferManager xfer_mgr = TransferManagerBuilder.standard().build();
try {
    MultipleFileUpload xfer = xfer_mgr.uploadFileList(bucket_name,
            key_prefix, new File("."), files);
    // loop with Transfer.isDone()
    XferMgrProgress.showTransferProgress(xfer);
    // or block with Transfer.waitForCompletion()
    XferMgrProgress.waitForCompletion(xfer);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
xfer_mgr.shutdownNow();
```

请参阅[等待传输完成](#transfermanager-wait-for-completion)以了解有关在调用 TransferManager 的 `shutdownNow` 方法之前使用 `waitForCompletion` 成功完成传输的信息。在等待传输完成时，您可以轮询或侦听有关其状态和进度的更新。有关更多信息，请参阅[获取传输状态和进度](#transfermanager-get-status-and-progress)。

可使用由 `uploadFileList` 返回的 [MultipleFileUpload](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/MultipleFileUpload.html) 对象来查询传输状态或进度。有关更多信息，请参阅[轮询传输的当前进度](#transfermanager-get-progress-polling)和[使用 ProgressListener 获取传输进度](#transfermanager-progress-listener)。

您也可以使用 `MultipleFileUpload` 的 `getSubTransfers` 方法为要传输的每个文件获取单个 `Upload` 对象。有关更多信息，请参阅[获取子传输的进度](#transfermanager-get-subtransfer-progress)。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/XferMgrUpload.java)。

### 上传目录
<a name="transfermanager-upload-directory"></a>

可使用 TransferManager 的 `uploadDirectory` 方法通过用于以递归方式复制子目录中的文件的选项来上传整个文件目录。您提供一个 Amazon S3 存储桶名称、一个 S3 键前缀、一个表示要复制的本地目录的 [File](https://docs.oracle.com/javase/8/docs/api/index.html?java/io/File.html) 对象和一个 `boolean` 值，该值指示您是否需要以递归方式复制子目录（*true* 或 *false*）。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.transfer.MultipleFileUpload;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.TransferManagerBuilder;
import com.amazonaws.services.s3.transfer.Upload;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
```

 **代码** 

```
TransferManager xfer_mgr = TransferManagerBuilder.standard().build();
try {
    MultipleFileUpload xfer = xfer_mgr.uploadDirectory(bucket_name,
            key_prefix, new File(dir_path), recursive);
    // loop with Transfer.isDone()
    XferMgrProgress.showTransferProgress(xfer);
    // or block with Transfer.waitForCompletion()
    XferMgrProgress.waitForCompletion(xfer);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
xfer_mgr.shutdownNow();
```

请参阅[等待传输完成](#transfermanager-wait-for-completion)以了解有关在调用 TransferManager 的 `shutdownNow` 方法之前使用 `waitForCompletion` 成功完成传输的信息。在等待传输完成时，您可以轮询或侦听有关其状态和进度的更新。有关更多信息，请参阅[获取传输状态和进度](#transfermanager-get-status-and-progress)。

可使用由 `uploadFileList` 返回的 [MultipleFileUpload](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/MultipleFileUpload.html) 对象来查询传输状态或进度。有关更多信息，请参阅[轮询传输的当前进度](#transfermanager-get-progress-polling)和[使用 ProgressListener 获取传输进度](#transfermanager-progress-listener)。

您也可以使用 `MultipleFileUpload` 的 `getSubTransfers` 方法为要传输的每个文件获取单个 `Upload` 对象。有关更多信息，请参阅[获取子传输的进度](#transfermanager-get-subtransfer-progress)。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/XferMgrUpload.java)。

## 下载文件或目录
<a name="transfermanager-downloading"></a>

使用 TransferManager 类从 Amazon S3 下载单个文件（Amazon S3 对象）或目录（一个 Amazon S3 桶名称，后跟对象前缀）。

**Topics**
+ [下载单个文件](#transfermanager-download-file)
+ [下载目录](#tranfermanager-download-directory)

### 下载单个文件
<a name="transfermanager-download-file"></a>

使用 TransferManager 的 `download` 方法，并为其提供包含要下载的对象的 Amazon S3 桶名称、键（对象）名称和一个 [File](https://docs.oracle.com/javase/8/docs/api/index.html?java/io/File.html) 对象（该对象表示要在本地系统上创建的文件）。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.transfer.Download;
import com.amazonaws.services.s3.transfer.MultipleFileDownload;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.TransferManagerBuilder;

import java.io.File;
```

 **代码** 

```
File f = new File(file_path);
TransferManager xfer_mgr = TransferManagerBuilder.standard().build();
try {
    Download xfer = xfer_mgr.download(bucket_name, key_name, f);
    // loop with Transfer.isDone()
    XferMgrProgress.showTransferProgress(xfer);
    // or block with Transfer.waitForCompletion()
    XferMgrProgress.waitForCompletion(xfer);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
xfer_mgr.shutdownNow();
```

请参阅[等待传输完成](#transfermanager-wait-for-completion)以了解有关在调用 TransferManager 的 `shutdownNow` 方法之前使用 `waitForCompletion` 成功完成传输的信息。在等待传输完成时，您可以轮询或侦听有关其状态和进度的更新。有关更多信息，请参阅[获取传输状态和进度](#transfermanager-get-status-and-progress)。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/XferMgrDownload.java)。

### 下载目录
<a name="tranfermanager-download-directory"></a>

要从 Amazon S3 下载一组共享一个公共键前缀的文件（类似于文件系统上的目录），可使用 TransferManager `downloadDirectory` 方法。该方法需要包含要下载的对象的 Amazon S3 存储桶名称、所有对象共享的对象前缀和一个 [File](https://docs.oracle.com/javase/8/docs/api/index.html?java/io/File.html) 对象（此对象表示要将文件下载到的本地系统目录）。如果指定目录尚不存在，将创建此目录。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.transfer.Download;
import com.amazonaws.services.s3.transfer.MultipleFileDownload;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.TransferManagerBuilder;

import java.io.File;
```

 **代码** 

```
TransferManager xfer_mgr = TransferManagerBuilder.standard().build();

try {
    MultipleFileDownload xfer = xfer_mgr.downloadDirectory(
            bucket_name, key_prefix, new File(dir_path));
    // loop with Transfer.isDone()
    XferMgrProgress.showTransferProgress(xfer);
    // or block with Transfer.waitForCompletion()
    XferMgrProgress.waitForCompletion(xfer);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
xfer_mgr.shutdownNow();
```

请参阅[等待传输完成](#transfermanager-wait-for-completion)以了解有关在调用 TransferManager 的 `shutdownNow` 方法之前使用 `waitForCompletion` 成功完成传输的信息。在等待传输完成时，您可以轮询或侦听有关其状态和进度的更新。有关更多信息，请参阅[获取传输状态和进度](#transfermanager-get-status-and-progress)。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/XferMgrDownload.java)。

## 复制对象
<a name="transfermanager-copy-object"></a>

要将对象从一个 S3 桶复制到另一个 S3 桶，可使用 TransferManager `copy` 方法。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.transfer.Copy;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.TransferManagerBuilder;
```

 **代码** 

```
System.out.println("Copying s3 object: " + from_key);
System.out.println("      from bucket: " + from_bucket);
System.out.println("     to s3 object: " + to_key);
System.out.println("        in bucket: " + to_bucket);

TransferManager xfer_mgr = TransferManagerBuilder.standard().build();
try {
    Copy xfer = xfer_mgr.copy(from_bucket, from_key, to_bucket, to_key);
    // loop with Transfer.isDone()
    XferMgrProgress.showTransferProgress(xfer);
    // or block with Transfer.waitForCompletion()
    XferMgrProgress.waitForCompletion(xfer);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
xfer_mgr.shutdownNow();
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/XferMgrCopy.java)。

## 请等待传输完成。
<a name="transfermanager-wait-for-completion"></a>

如果可以在传输完成前阻止您的应用程序（或线程），则可使用 [Transfer](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/Transfer.html) 接口的 `waitForCompletion` 方法来阻止它，直至传输完成或出现异常。

```
try {
    xfer.waitForCompletion();
} catch (AmazonServiceException e) {
    System.err.println("Amazon service error: " + e.getMessage());
    System.exit(1);
} catch (AmazonClientException e) {
    System.err.println("Amazon client error: " + e.getMessage());
    System.exit(1);
} catch (InterruptedException e) {
    System.err.println("Transfer interrupted: " + e.getMessage());
    System.exit(1);
}
```

如果您在调用 * *之前`waitForCompletion` 轮询事件、在单独线程上实施轮询机制或使用 [ProgressListener](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/event/ProgressListener.html) 异步接收进度更新，则可获取传输进度。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/XferMgrProgress.java)。

## 获取传输状态和进度
<a name="transfermanager-get-status-and-progress"></a>

TransferManager `upload*`、`download*` 和 `copy` 方法所返回的每个类均返回以下某个类的实例，具体取决于它是单文件操作还是多文件操作。


**​**  

| 类 | 返回方 | 
| --- | --- | 
|   [Copy（复制](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/Copy.html)   |   `copy`   | 
|   [下载](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/Download.html) 。  |   `download`   | 
|   [MultipleFileDownload](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/MultipleFileDownload.html)   |   `downloadDirectory`   | 
|   [上传](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/Upload.html)   |   `upload`   | 
|   [MultipleFileUpload](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/MultipleFileUpload.html)   |   `uploadFileList`, `uploadDirectory`   | 

所有这些类都实施 [Transfer](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/Transfer.html) 接口。`Transfer` 提供了用于获取传输进度、暂停或恢复传输以及获取传输的当前状态或最终状态的有用方法。

**Topics**
+ [轮询传输的当前进度](#transfermanager-get-progress-polling)
+ [使用 ProgressListener 获取传输进度](#transfermanager-progress-listener)
+ [获取子传输的进度](#transfermanager-get-subtransfer-progress)

### 轮询传输的当前进度
<a name="transfermanager-get-progress-polling"></a>

此循环打印传输的进度，在其运行时检查其当前进度，然后在传输完成时打印最终状态。

 **导入**。

```
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.event.ProgressEvent;
import com.amazonaws.event.ProgressListener;
import com.amazonaws.services.s3.transfer.*;
import com.amazonaws.services.s3.transfer.Transfer.TransferState;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
```

 **代码** 

```
// print the transfer's human-readable description
System.out.println(xfer.getDescription());
// print an empty progress bar...
printProgressBar(0.0);
// update the progress bar while the xfer is ongoing.
do {
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        return;
    }
    // Note: so_far and total aren't used, they're just for
    // documentation purposes.
    TransferProgress progress = xfer.getProgress();
    long so_far = progress.getBytesTransferred();
    long total = progress.getTotalBytesToTransfer();
    double pct = progress.getPercentTransferred();
    eraseProgressBar();
    printProgressBar(pct);
} while (xfer.isDone() == false);
// print the final state of the transfer.
TransferState xfer_state = xfer.getState();
System.out.println(": " + xfer_state);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/XferMgrProgress.java)。

### 使用 ProgressListener 获取传输进度
<a name="transfermanager-progress-listener"></a>

您可以使用 [Transfer](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/Transfer.html) 接口的 `addProgressListener` 方法将 [ProgressListener](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/event/ProgressListener.html) 附加到任何传输中。

[ProgressListener](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/event/ProgressListener.html) 只需要一个方法，即 `progressChanged`，此方法将采用 [ProgressEvent](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/event/ProgressEvent.html) 对象。您可以使用此对象获取操作的总字节数 (通过调用其 `getBytes` 方法) 和目前已传输的字节数 (通过调用 `getBytesTransferred`)。

 **导入**。

```
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.event.ProgressEvent;
import com.amazonaws.event.ProgressListener;
import com.amazonaws.services.s3.transfer.*;
import com.amazonaws.services.s3.transfer.Transfer.TransferState;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
```

 **代码** 

```
File f = new File(file_path);
TransferManager xfer_mgr = TransferManagerBuilder.standard().build();
try {
    Upload u = xfer_mgr.upload(bucket_name, key_name, f);
    // print an empty progress bar...
    printProgressBar(0.0);
    u.addProgressListener(new ProgressListener() {
        public void progressChanged(ProgressEvent e) {
            double pct = e.getBytesTransferred() * 100.0 / e.getBytes();
            eraseProgressBar();
            printProgressBar(pct);
        }
    });
    // block with Transfer.waitForCompletion()
    XferMgrProgress.waitForCompletion(u);
    // print the final state of the transfer.
    TransferState xfer_state = u.getState();
    System.out.println(": " + xfer_state);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
xfer_mgr.shutdownNow();
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/XferMgrProgress.java)。

### 获取子传输的进度
<a name="transfermanager-get-subtransfer-progress"></a>

[MultipleFileUpload](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/MultipleFileUpload.html) 类可通过调用其 `getSubTransfers` 方法来返回有关其子传输的信息。它将返回 [Upload](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Collection.html) 对象的不可修改的 [Collection](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/transfer/Upload.html)，并单独提供每个子传输的传输状态和进度。

 **导入**。

```
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.event.ProgressEvent;
import com.amazonaws.event.ProgressListener;
import com.amazonaws.services.s3.transfer.*;
import com.amazonaws.services.s3.transfer.Transfer.TransferState;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
```

 **代码** 

```
Collection<? extends Upload> sub_xfers = new ArrayList<Upload>();
sub_xfers = multi_upload.getSubTransfers();

do {
    System.out.println("\nSubtransfer progress:\n");
    for (Upload u : sub_xfers) {
        System.out.println("  " + u.getDescription());
        if (u.isDone()) {
            TransferState xfer_state = u.getState();
            System.out.println("  " + xfer_state);
        } else {
            TransferProgress progress = u.getProgress();
            double pct = progress.getPercentTransferred();
            printProgressBar(pct);
            System.out.println();
        }
    }

    // wait a bit before the next update.
    try {
        Thread.sleep(200);
    } catch (InterruptedException e) {
        return;
    }
} while (multi_upload.isDone() == false);
// print the final state of the transfer.
TransferState xfer_state = multi_upload.getState();
System.out.println("\nMultipleFileUpload " + xfer_state);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/XferMgrProgress.java)。

## 更多信息
<a name="transfermanager-see-also"></a>
+  《Amazon Simple Storage Service 用户指南》中的[对象键](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html)

# 将 Amazon S3 桶配置为网站
<a name="examples-s3-website-configuration"></a>

您可以配置 Amazon S3 存储桶，使其具有与网站类似的行为。要执行此操作，您需要设置其网站配置。

**注意**  
这些代码示例假定您了解[使用适用于 Java 的 AWS SDK](basics.md) 中的内容，并且已使用[设置用于开发的 AWS 凭证和区域](setup-credentials.md)中的信息配置默认 AWS 凭证。

## 设置存储桶的网站配置
<a name="set-a-bucket-s-website-configuration"></a>

要设置 Amazon S3 桶网站配置，请使用要设置配置的桶名称，以及包含桶网站配置的 [BucketWebsiteConfiguration](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/BucketWebsiteConfiguration.html) 对象，来调用 AmazonS3 的 `setWebsiteConfiguration` 方法。

设置索引文档是*必需的*；所有其他参数都是可选的。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.BucketWebsiteConfiguration;
```

 **代码** 

```
    String bucket_name, String index_doc, String error_doc) {
BucketWebsiteConfiguration website_config = null;

if (index_doc == null) {
    website_config = new BucketWebsiteConfiguration();
} else if (error_doc == null) {
    website_config = new BucketWebsiteConfiguration(index_doc);
} else {
    website_config = new BucketWebsiteConfiguration(index_doc, error_doc);
}

final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
try {
    s3.setBucketWebsiteConfiguration(bucket_name, website_config);
} catch (AmazonServiceException e) {
    System.out.format(
            "Failed to set website configuration for bucket '%s'!\n",
            bucket_name);
    System.err.println(e.getErrorMessage());
    System.exit(1);
}
```

**注意**  
设置网站配置不会修改您的存储桶的访问权限。要使您的文件在 Web 上可见，您还需要设置一个*存储桶策略*，允许对存储桶中文件的公共读取访问权限。有关更多信息，请参阅[使用桶策略管理对 Amazon S3 桶的访问](examples-s3-bucket-policies.md)。

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/SetWebsiteConfiguration.java)。

## 获取存储桶的网站配置
<a name="get-a-bucket-s-website-configuration"></a>

要获取 Amazon S3 桶的网站配置，请使用要检索其配置的桶的名称来调用 AmazonS3 的 `getWebsiteConfiguration` 方法。

将以 [BucketWebsiteConfiguration](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/BucketWebsiteConfiguration.html) 对象的形式返回配置。如果该存储桶没有网站配置，则会返回 `null`。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.BucketWebsiteConfiguration;
```

 **代码** 

```
final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
try {
    BucketWebsiteConfiguration config =
            s3.getBucketWebsiteConfiguration(bucket_name);
    if (config == null) {
        System.out.println("No website configuration found!");
    } else {
        System.out.format("Index document: %s\n",
                config.getIndexDocumentSuffix());
        System.out.format("Error document: %s\n",
                config.getErrorDocument());
    }
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.out.println("Failed to get website configuration!");
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/GetWebsiteConfiguration.java)。

## 删除存储桶的网站配置
<a name="delete-a-bucket-s-website-configuration"></a>

要删除 Amazon S3 桶的网站配置，请使用要从中删除配置的桶的名称来调用 AmazonS3 的 `deleteWebsiteConfiguration` 方法。

 **导入**。

```
import com.amazonaws.AmazonServiceException;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
```

 **代码** 

```
final AmazonS3 s3 = AmazonS3ClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
try {
    s3.deleteBucketWebsiteConfiguration(bucket_name);
} catch (AmazonServiceException e) {
    System.err.println(e.getErrorMessage());
    System.out.println("Failed to delete website configuration!");
    System.exit(1);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/DeleteWebsiteConfiguration.java)。

## 更多信息
<a name="more-information"></a>
+  《Amazon S3 API Reference》中的 [PUT Bucket website](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTwebsite.html)
+  《Amazon S3 API Reference》中的 [GET Bucket website](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETwebsite.html)
+  《Amazon S3 API Reference》中的 [DELETE Bucket website](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketDELETEwebsite.html)

# 使用 Amazon S3 客户端加密
<a name="examples-crypto"></a>

使用 Amazon S3 加密客户端加密数据是您可以用于为存储在 Amazon S3 中的敏感信息提供一层额外保护的一种方法。此部分中的示例演示如何为您的应用程序创建和配置 Amazon S3 加密客户端。

如果您不熟悉加密，请参阅《AWS KMS 开发人员指南》中的[加密基础知识](https://docs.aws.amazon.com/kms/latest/developerguide/crypto-intro.html)，大致了解加密术语和加密算法。要了解有关所有 AWS SDK 的加密支持信息，请参阅 Amazon Web Services 一般参考中的 [Amazon S3 客户端加密的 AWS SDK 支持](https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html)。

**注意**  
这些代码示例假定您了解[使用适用于 Java 的 AWS SDK](basics.md) 中的内容，并且已使用[设置用于开发的 AWS 凭证和区域](setup-credentials.md)中的信息配置默认 AWS 凭证。

如果您使用的是 1.11.836 或更低版本的适用于 Java 的 AWS SDK，请参阅 [Amazon S3 加密客户端迁移](s3-encryption-migration.md)，了解有关将应用程序迁移到更高版本的信息。如果您无法迁移，请参阅 GitHub 上的[此完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/s3/src/main/java/aws/example/s3/S3Encrypt.java)。

如果您使用的是 1.11.837 或更高版本的适用于 Java 的 AWS SDK，请浏览下面列出的示例主题以使用 Amazon S3 客户端加密。

**Topics**
+ [Amazon S3 客户端加密配合客户端主密钥](examples-crypto-masterkey.md)
+ [Amazon S3 客户端加密配合 AWS KMS 托管密钥](examples-crypto-kms.md)

# Amazon S3 客户端加密配合客户端主密钥
<a name="examples-crypto-masterkey"></a>

以下示例使用 [AmazonS3EncryptionClientV2Builder](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/AmazonS3EncryptionClientV2Builder.html) 类创建启用客户端加密的 Amazon S3 客户端。启用后，您使用此客户端上传到 Amazon S3 的任何对象都将加密。您使用此客户端从 Amazon S3 获取的任何对象都将自动解密。

**注意**  
以下示例演示如何配合使用 Amazon S3 客户端加密和客户托管的客户端主密钥。要了解如何配合使用加密和 AWS KMS 托管密钥，请参阅 [Amazon S3 客户端加密配合 AWS 托管密钥](examples-crypto-kms.md)。

启用客户端 Amazon S3 加密时，您可以从两种加密模式中进行选择：经严格身份验证或经身份验证。以下部分说明了如何启用每种类型。要了解每种模式使用哪种算法，请参阅 [CryptoMode](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/CryptoMode.html) 定义。

## 必需的导入
<a name="required-imports"></a>

为这些示例导入以下类。

 **导入**。

```
import com.amazonaws.ClientConfiguration;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3EncryptionClientV2Builder;
import com.amazonaws.services.s3.AmazonS3EncryptionV2;
import com.amazonaws.services.s3.model.CryptoConfigurationV2;
import com.amazonaws.services.s3.model.CryptoMode;
import com.amazonaws.services.s3.model.EncryptionMaterials;
import com.amazonaws.services.s3.model.StaticEncryptionMaterialsProvider;
```

## 经严格身份验证加密
<a name="strict-authenticated-encryption"></a>

如果未指定 `CryptoMode`，则默认模式为经严格身份验证加密。

要显式启用此模式，请在 `withCryptoConfiguration` 方法中指定 `StrictAuthenticatedEncryption` 值。

**注意**  
要使用客户端经身份验证加密，您必须将最新的 [Bouncy Castle jar](https://www.bouncycastle.org/download/bouncy-castle-java/) 文件加入应用程序的类路径中。

 **代码** 

```
AmazonS3EncryptionV2 s3Encryption = AmazonS3EncryptionClientV2Builder.standard()
         .withRegion(Regions.US_WEST_2)
         .withCryptoConfiguration(new CryptoConfigurationV2().withCryptoMode((CryptoMode.StrictAuthenticatedEncryption)))
         .withEncryptionMaterialsProvider(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(secretKey)))
         .build();

s3Encryption.putObject(bucket_name, ENCRYPTED_KEY2, "This is the 2nd content to encrypt");
```

## 经身份验证加密模式
<a name="authenticated-encryption-mode"></a>

使用 `AuthenticatedEncryption` 模式时，在加密期间会应用改进的密钥包装算法。在此模式下解密时，该算法会验证已解密对象的完整性，如果检查失败，则引发异常。有关经身份验证加密模式工作原理的更多详细信息，请参阅博客文章 [Amazon S3 Client-Side Authenticated Encryption](https://aws.amazon.com/blogs/developer/amazon-s3-client-side-authenticated-encryption)。

**注意**  
要使用客户端经身份验证加密，您必须将最新的 [Bouncy Castle jar](https://www.bouncycastle.org/download/bouncy-castle-java/) 文件加入应用程序的类路径中。

要启用此模式，请在 `AuthenticatedEncryption` 方法中指定 `withCryptoConfiguration` 值。

 **代码** 

```
AmazonS3EncryptionV2 s3EncryptionClientV2 = AmazonS3EncryptionClientV2Builder.standard()
         .withRegion(Regions.DEFAULT_REGION)
         .withClientConfiguration(new ClientConfiguration())
         .withCryptoConfiguration(new CryptoConfigurationV2().withCryptoMode(CryptoMode.AuthenticatedEncryption))
         .withEncryptionMaterialsProvider(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(secretKey)))
         .build();

s3EncryptionClientV2.putObject(bucket_name, ENCRYPTED_KEY1, "This is the 1st content to encrypt");
```

# Amazon S3 客户端加密配合 AWS KMS 托管密钥
<a name="examples-crypto-kms"></a>

以下示例使用 [AmazonS3EncryptionClientV2Builder](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/AmazonS3EncryptionClientV2Builder.html) 类创建启用客户端加密的 Amazon S3 客户端。配置后，您使用此客户端上传到 Amazon S3 的任何对象都将加密。您使用此客户端从 Amazon S3 获取的任何对象都将自动解密。

**注意**  
以下示例演示如何将 Amazon S3 客户端加密和 AWS 托管密钥配合使用。要了解如何将加密与您自己的密钥配合使用，请参阅 [Amazon S3 客户端加密配合客户端主密钥](examples-crypto-masterkey.md)。

启用客户端 Amazon S3 加密时，您可以从两种加密模式中进行选择：经严格身份验证或经身份验证。以下部分说明了如何启用每种类型。要了解每种模式使用哪种算法，请参阅 [CryptoMode](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/s3/model/CryptoMode.html) 定义。

## 必需的导入
<a name="required-imports"></a>

为这些示例导入以下类。

 **导入**。

```
import com.amazonaws.ClientConfiguration;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.kms.AWSKMS;
import com.amazonaws.services.kms.AWSKMSClientBuilder;
import com.amazonaws.services.kms.model.GenerateDataKeyRequest;
import com.amazonaws.services.kms.model.GenerateDataKeyResult;
import com.amazonaws.services.s3.AmazonS3EncryptionClientV2Builder;
import com.amazonaws.services.s3.AmazonS3EncryptionV2;
import com.amazonaws.services.s3.model.CryptoConfigurationV2;
import com.amazonaws.services.s3.model.CryptoMode;
import com.amazonaws.services.s3.model.EncryptionMaterials;
import com.amazonaws.services.s3.model.KMSEncryptionMaterialsProvider;
```

## 经严格身份验证加密
<a name="strict-authenticated-encryption-kms"></a>

如果未指定 `CryptoMode`，则默认模式为经严格身份验证加密。

要显式启用此模式，请在 `withCryptoConfiguration` 方法中指定 `StrictAuthenticatedEncryption` 值。

**注意**  
要使用客户端经身份验证加密，您必须将最新的 [Bouncy Castle jar](https://www.bouncycastle.org/download/bouncy-castle-java/) 文件加入应用程序的类路径中。

 **代码** 

```
AmazonS3EncryptionV2 s3Encryption = AmazonS3EncryptionClientV2Builder.standard()
         .withRegion(Regions.US_WEST_2)
         .withCryptoConfiguration(new CryptoConfigurationV2().withCryptoMode((CryptoMode.StrictAuthenticatedEncryption)))
         .withEncryptionMaterialsProvider(new KMSEncryptionMaterialsProvider(keyId))
         .build();

s3Encryption.putObject(bucket_name, ENCRYPTED_KEY3, "This is the 3rd content to encrypt with a key created in the {console}");
System.out.println(s3Encryption.getObjectAsString(bucket_name, ENCRYPTED_KEY3));
```

对 `putObject` 加密客户端调用 Amazon S3 方法以上传对象。

 **代码** 

```
s3Encryption.putObject(bucket_name, ENCRYPTED_KEY3, "This is the 3rd content to encrypt with a key created in the {console}");
```

您可以使用同一个客户端检索该对象。此示例调用 `getObjectAsString` 方法以检索存储的字符串。

 **代码** 

```
System.out.println(s3Encryption.getObjectAsString(bucket_name, ENCRYPTED_KEY3));
```

## 经身份验证加密模式
<a name="authenticated-encryption-kms"></a>

使用 `AuthenticatedEncryption` 模式时，在加密期间会应用改进的密钥包装算法。在此模式下解密时，该算法会验证已解密对象的完整性，如果检查失败，则引发异常。有关经身份验证加密模式工作原理的更多详细信息，请参阅博客文章 [Amazon S3 Client-Side Authenticated Encryption](https://aws.amazon.com/blogs/developer/amazon-s3-client-side-authenticated-encryption)。

**注意**  
要使用客户端经身份验证加密，您必须将最新的 [Bouncy Castle jar](https://www.bouncycastle.org/download/bouncy-castle-java/) 文件加入应用程序的类路径中。

要启用此模式，请在 `AuthenticatedEncryption` 方法中指定 `withCryptoConfiguration` 值。

 **代码** 

```
AmazonS3EncryptionV2 s3Encryption = AmazonS3EncryptionClientV2Builder.standard()
         .withRegion(Regions.US_WEST_2)
         .withCryptoConfiguration(new CryptoConfigurationV2().withCryptoMode((CryptoMode.AuthenticatedEncryption)))
         .withEncryptionMaterialsProvider(new KMSEncryptionMaterialsProvider(keyId))
         .build();
```

## 配置 AWS KMS 客户端
<a name="configure-kms"></a>

除非明确指定了 AWS KMS 客户端，否则默认情况下，Amazon S3 加密客户端会创建一个该客户端。

要为这个自动创建的 AWS KMS 客户端设置区域，请设置 `awsKmsRegion`。

 **代码** 

```
Region kmsRegion = Region.getRegion(Regions.AP_NORTHEAST_1);

AmazonS3EncryptionV2 s3Encryption = AmazonS3EncryptionClientV2Builder.standard()
        .withRegion(Regions.US_WEST_2)
        .withCryptoConfiguration(new CryptoConfigurationV2().withAwsKmsRegion(kmsRegion))
        .withEncryptionMaterialsProvider(new KMSEncryptionMaterialsProvider(keyId))
        .build();
```

或者，您可以使用自己的 AWS KMS 客户端来初始化加密客户端。

 **代码** 

```
AWSKMS kmsClient = AWSKMSClientBuilder.standard()
        .withRegion(Regions.US_WEST_2);
        .build();

AmazonS3EncryptionV2 s3Encryption = AmazonS3EncryptionClientV2Builder.standard()
        .withRegion(Regions.US_WEST_2)
        .withKmsClient(kmsClient)
        .withCryptoConfiguration(new CryptoConfigurationV2().withCryptoMode((CryptoMode.AuthenticatedEncryption)))
        .withEncryptionMaterialsProvider(new KMSEncryptionMaterialsProvider(keyId))
        .build();
```

# 使用适用于 Java 的 AWS SDK 的 Amazon SQS 示例
<a name="examples-sqs"></a>

此部分提供使用[适用于 Java 的 AWS SDK](https://aws.amazon.com/sdk-for-java/) 对 [Amazon SQS](https://aws.amazon.com/sqs/) 进行编程的示例。

**注意**  
这些示例仅包含演示每种方法所需的代码。[完整的示例代码在 GitHub 上提供](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/java)。您可以在那里下载单个源文件，也可以将存储库复制到本地以获得所有示例，然后构建并运行这些示例。

**Topics**
+ [使用 Amazon SQS 消息队列](examples-sqs-message-queues.md)
+ [发送、接收和删除 Amazon SQS 消息](examples-sqs-messages.md)
+ [为 Amazon SQS 消息队列启用长轮询](examples-sqs-long-polling.md)
+ [在 Amazon SQS 中设置可见性超时](examples-sqs-visibility-timeout.md)
+ [在 Amazon SQS 中使用死信队列](examples-sqs-dead-letter-queues.md)

# 使用 Amazon SQS 消息队列
<a name="examples-sqs-message-queues"></a>

*消息队列* 是用于在 Amazon SQS 中可靠地发送消息的逻辑容器。有两种类型的队列：*标准* 和*先进先出* (FIFO)。要了解有关队列以及这些类型之间的差异的更多信息，请参阅《[Amazon SQS Developer Guide](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/)》。

本主题介绍如何使用适用于 Java 的 AWS SDK 来创建、列出、删除和获取 Amazon SQS 队列的 URL。

## 创建队列
<a name="sqs-create-queue"></a>

请使用 AmazonSQS 客户端的 `createQueue` 方法，并提供一个描述队列参数的 [CreateQueueRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/CreateQueueRequest.html) 对象。

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.AmazonSQSException;
import com.amazonaws.services.sqs.model.CreateQueueRequest;
```

 **代码** 

```
AmazonSQS sqs = AmazonSQSClientBuilder.defaultClient();
CreateQueueRequest create_request = new CreateQueueRequest(QUEUE_NAME)
        .addAttributesEntry("DelaySeconds", "60")
        .addAttributesEntry("MessageRetentionPeriod", "86400");

try {
    sqs.createQueue(create_request);
} catch (AmazonSQSException e) {
    if (!e.getErrorCode().equals("QueueAlreadyExists")) {
        throw e;
    }
}
```

您可以使用 `createQueue` 的简化形式，这只需要队列名称即可创建标准队列。

```
sqs.createQueue("MyQueue" + new Date().getTime());
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/UsingQueues.java)。

## 列出队列
<a name="sqs-list-queues"></a>

要列出您的账户的 Amazon SQS 队列，可调用 AmazonSQS 客户端的 `listQueues` 方法。

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.ListQueuesResult;
```

 **代码** 

```
AmazonSQS sqs = AmazonSQSClientBuilder.defaultClient();
ListQueuesResult lq_result = sqs.listQueues();
System.out.println("Your SQS Queue URLs:");
for (String url : lq_result.getQueueUrls()) {
    System.out.println(url);
}
```

使用 `listQueues` 重载 (不带任何参数) 将返回*所有队列*。您可以通过向其传递一个 `ListQueuesRequest` 对象来筛选返回的结果。

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.ListQueuesRequest;
```

 **代码** 

```
AmazonSQS sqs = AmazonSQSClientBuilder.defaultClient();
String name_prefix = "Queue";
lq_result = sqs.listQueues(new ListQueuesRequest(name_prefix));
System.out.println("Queue URLs with prefix: " + name_prefix);
for (String url : lq_result.getQueueUrls()) {
    System.out.println(url);
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/UsingQueues.java)。

## 获取队列的 URL
<a name="sqs-get-queue-url"></a>

调用 AmazonSQS 客户端的 `getQueueUrl` 方法。

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
```

 **代码** 

```
AmazonSQS sqs = AmazonSQSClientBuilder.defaultClient();
String queue_url = sqs.getQueueUrl(QUEUE_NAME).getQueueUrl();
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/UsingQueues.java)。

## 删除队列
<a name="sqs-delete-queue"></a>

向 AmazonSQS 客户端的 `deleteQueue` 方法提供队列的 [URL](#sqs-get-queue-url)。

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
```

 **代码** 

```
AmazonSQS sqs = AmazonSQSClientBuilder.defaultClient();
sqs.deleteQueue(queue_url);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/UsingQueues.java)。

## 更多信息
<a name="more-info"></a>
+  《Amazon SQS Developer Guide》中的 [How Amazon SQS Queues Work](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-how-it-works.html)
+  《Amazon SQS API Reference》中的 [CreateQueue](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_CreateQueue.html)
+  《Amazon SQS API Reference》中的 [GetQueueUrl](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_GetQueueUrl.html)
+  《Amazon SQS API Reference》中的 [ListQueues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ListQueues.html)
+  《Amazon SQS API Reference》中的 [DeleteQueues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteQueues.html)

# 发送、接收和删除 Amazon SQS 消息
<a name="examples-sqs-messages"></a>

本主题描述了如何发送、接收和删除 Amazon SQS 消息。始终使用 [SQS 队列](examples-sqs-message-queues.md)发送消息。

## 发送消息
<a name="sqs-message-send"></a>

通过调用 AmazonSQS 客户端的 `sendMessage` 方法，将单个消息添加到 Amazon SQS 队列。提供包含队列 [URL](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/SendMessageRequest.html)、消息正文和可选延迟值（以秒为单位）的 [SendMessageRequest](examples-sqs-message-queues.md#sqs-get-queue-url) 对象。

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.SendMessageRequest;
```

 **代码** 

```
SendMessageRequest send_msg_request = new SendMessageRequest()
        .withQueueUrl(queueUrl)
        .withMessageBody("hello world")
        .withDelaySeconds(5);
sqs.sendMessage(send_msg_request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/SendReceiveMessages.java)。

### 一次性发送多条消息
<a name="sqs-messages-send-multiple"></a>

您可以在一个请求中发送多条消息。要发送多条消息，可使用 AmazonSQS 客户端的 `sendMessageBatch` 方法，此方法采用 [SendMessageBatchRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/SendMessageBatchRequest.html)，后者包含队列 URL 和要发送的消息列表（每条消息对应一个 [SendMessageBatchRequestEntry](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/SendMessageBatchRequestEntry.html)）。您也可以为每条消息设置一个可选延迟值。

 **导入**。

```
import com.amazonaws.services.sqs.model.SendMessageBatchRequest;
import com.amazonaws.services.sqs.model.SendMessageBatchRequestEntry;
```

 **代码** 

```
SendMessageBatchRequest send_batch_request = new SendMessageBatchRequest()
        .withQueueUrl(queueUrl)
        .withEntries(
                new SendMessageBatchRequestEntry(
                        "msg_1", "Hello from message 1"),
                new SendMessageBatchRequestEntry(
                        "msg_2", "Hello from message 2")
                        .withDelaySeconds(10));
sqs.sendMessageBatch(send_batch_request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/SendReceiveMessages.java)。

## 接收消息
<a name="sqs-messages-receive"></a>

可通过调用 AmazonSQS 客户端的 `receiveMessage` 方法并为其传递队列的 URL，来检索当前位于队列中的任何消息。消息将作为一系列 [Message](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/Message.html) 对象返回。

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.AmazonSQSException;
import com.amazonaws.services.sqs.model.SendMessageBatchRequest;
```

 **代码** 

```
List<Message> messages = sqs.receiveMessage(queueUrl).getMessages();
```

## 收到后删除消息
<a name="sqs-messages-delete"></a>

在收到消息并处理其内容后，可通过将消息的接收句柄和队列 URL 发送到 AmazonSQS 客户端的 `deleteMessage` 方法来从队列中删除消息。

 **代码** 

```
for (Message m : messages) {
    sqs.deleteMessage(queueUrl, m.getReceiptHandle());
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/SendReceiveMessages.java)。

## 更多信息
<a name="more-info"></a>
+  《Amazon SQS Developer Guide》中的 [How Amazon SQS Queues Work](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-how-it-works.html)
+  《Amazon SQS API Reference》中的 [SendMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)
+  《Amazon SQS API Reference》中的 [SendMessageBatch](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessageBatch.html)
+  《Amazon SQS API Reference》中的 [ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html)
+  《Amazon SQS API Reference》中的 [DeleteMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_DeleteMessage.html)

# 为 Amazon SQS 消息队列启用长轮询
<a name="examples-sqs-long-polling"></a>

 默认情况下，Amazon SQS 使用*短轮询*，此时仅查询服务器的一个子集（基于加权随机分布），以确定是否有任何消息可包含在响应中。

长轮询有助于降低使用 Amazon SQS 的费用，它可在答复发送到 Amazon SQS 队列的 ReceiveMessage 请求时，减少因没有消息可返回而造成的空响应数，还可消除假的空响应。

**注意**  
您可以设置 *1 到 20 秒*的长轮询频率。

## 创建队列时启用长轮询
<a name="sqs-long-polling-create-queue"></a>

要在创建 Amazon SQS 队列时启用长轮询，请设置 [CreateQueueRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/CreateQueueRequest.html) 对象的 `ReceiveMessageWaitTimeSeconds` 属性，然后再调用 AmazonSQS 类的 `createQueue` 方法。

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.AmazonSQSException;
import com.amazonaws.services.sqs.model.CreateQueueRequest;
```

 **代码** 

```
final AmazonSQS sqs = AmazonSQSClientBuilder.defaultClient();

// Enable long polling when creating a queue
CreateQueueRequest create_request = new CreateQueueRequest()
        .withQueueName(queue_name)
        .addAttributesEntry("ReceiveMessageWaitTimeSeconds", "20");

try {
    sqs.createQueue(create_request);
} catch (AmazonSQSException e) {
    if (!e.getErrorCode().equals("QueueAlreadyExists")) {
        throw e;
    }
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/LongPolling.java)。

## 在现有队列上启用长轮询
<a name="sqs-long-polling-existing-queue"></a>

除了在创建队列时启用长轮询之外，您也可以通过在 [SetQueueAttributesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/SetQueueAttributesRequest.html) 上设置 `ReceiveMessageWaitTimeSeconds`，然后再调用 AmazonSQS 类的 `setQueueAttributes` 方法，在现有队列上启用长轮询。

 **导入**。

```
import com.amazonaws.services.sqs.model.SetQueueAttributesRequest;
```

 **代码** 

```
SetQueueAttributesRequest set_attrs_request = new SetQueueAttributesRequest()
        .withQueueUrl(queue_url)
        .addAttributesEntry("ReceiveMessageWaitTimeSeconds", "20");
sqs.setQueueAttributes(set_attrs_request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/LongPolling.java)。

## 在接收消息时启用长轮询
<a name="sqs-long-polling-receive-message"></a>

您可以在接收消息时启用长轮询，方法是在您提供给 AmazonSQS 类的 `receiveMessage` 方法的 [ReceiveMessageRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/ReceiveMessageRequest.html) 中设置等待时间（以秒为单位）。

**注意**  
您应确保 AWS 客户端的请求超时时间大于最大长轮询时间（20 秒），以确保您的 `receiveMessage` 请求在等待下一轮询事件时不会超时！

 **导入**。

```
import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
```

 **代码** 

```
ReceiveMessageRequest receive_request = new ReceiveMessageRequest()
        .withQueueUrl(queue_url)
        .withWaitTimeSeconds(20);
sqs.receiveMessage(receive_request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/LongPolling.java)。

## 更多信息
<a name="more-info"></a>
+  《Amazon SQS Developer Guide》中的 [Amazon SQS Long Polling](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-long-polling.html)
+  《Amazon SQS API Reference》中的 [CreateQueue](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_CreateQueue.html)
+  《Amazon SQS API Reference》中的 [ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html)
+  《Amazon SQS API Reference》中的 [SetQueueAttributes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SetQueueAttributes.html)

# 在 Amazon SQS 中设置可见性超时
<a name="examples-sqs-visibility-timeout"></a>

为了确保消息接收，在 Amazon SQS 中收到的消息会保留在队列中，直到被删除。在指定的*可见性超时*时间后，已接收但未删除的消息将可以在后续请求中使用，以帮助防止在对消息进行处理和删除之前重复接收消息。

**注意**  
使用[标准队列](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/standard-queues.html)时，可见性超时无法保证不会接收消息两次。如果您使用的是标准队列，请确保您的代码能够处理多次收到同一条消息的情况。

## 为单个消息设置消息可见性超时
<a name="sqs-visibility-timeout-receipt"></a>

当您收到消息时，您可以通过在 [ChangeMessageVisibilityRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/ChangeMessageVisibilityRequest.html) 中将消息的接收句柄传递到 AmazonSQS 类的 `changeMessageVisibility` 方法来修改其可见性超时。

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
```

 **代码** 

```
AmazonSQS sqs = AmazonSQSClientBuilder.defaultClient();

// Get the receipt handle for the first message in the queue.
String receipt = sqs.receiveMessage(queue_url)
                    .getMessages()
                    .get(0)
                    .getReceiptHandle();

sqs.changeMessageVisibility(queue_url, receipt, timeout);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/VisibilityTimeout.java)。

## 一次性为多条消息设置的消息可见性超时
<a name="setting-the-message-visibility-timeout-for-multiple-messages-at-once"></a>

要一次性设置多条消息的可见性超时，请创建 [ChangeMessageVisibilityBatchRequestEntry](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/ChangeMessageVisibilityBatchRequestEntry.html) 对象的列表，每个对象包含唯一的 ID 和接收句柄。然后将该列表传递给 Amazon SQS 客户端类的 `changeMessageVisibilityBatch` 方法。

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.ChangeMessageVisibilityBatchRequestEntry;
import java.util.ArrayList;
import java.util.List;
```

 **代码** 

```
AmazonSQS sqs = AmazonSQSClientBuilder.defaultClient();

List<ChangeMessageVisibilityBatchRequestEntry> entries =
    new ArrayList<ChangeMessageVisibilityBatchRequestEntry>();

entries.add(new ChangeMessageVisibilityBatchRequestEntry(
            "unique_id_msg1",
            sqs.receiveMessage(queue_url)
               .getMessages()
               .get(0)
               .getReceiptHandle())
        .withVisibilityTimeout(timeout));

entries.add(new ChangeMessageVisibilityBatchRequestEntry(
            "unique_id_msg2",
            sqs.receiveMessage(queue_url)
               .getMessages()
               .get(0)
               .getReceiptHandle())
        .withVisibilityTimeout(timeout + 200));

sqs.changeMessageVisibilityBatch(queue_url, entries);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/VisibilityTimeout.java)。

## 更多信息
<a name="more-info"></a>
+  《Amazon SQS Developer Guide》中的 [Visibility Timeout](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)
+  《Amazon SQS API Reference》中的 [SetQueueAttributes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SetQueueAttributes.html)
+  《Amazon SQS API Reference》中的 [GetQueueAttributes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_GetQueueAttributes.html)
+  《Amazon SQS API Reference》中的 [ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html)
+  《Amazon SQS API Reference》中的 [ChangeMessageVisibility](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ChangeMessageVisibility.html)
+  《Amazon SQS API Reference》中的 [ChangeMessageVisibilityBatch](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ChangeMessageVisibilityBatch.html)

# 在 Amazon SQS 中使用死信队列
<a name="examples-sqs-dead-letter-queues"></a>

 Amazon SQS 支持*死信队列*。死信队列是其他（源）队列可将其作为无法成功处理的消息的目标的队列。您可以在死信队列中留出和隔离这些消息以确定其处理失败的原因。

## 创建死信队列
<a name="sqs-dead-letter-queue-create-dl-queue"></a>

死信队列的创建方式与常规队列相同，但有以下限制：
+ 死信队列必须与源队列属于相同的队列类型 (FIFO 或标准)。
+ 死信队列必须与源队列使用相同的 AWS 账户和区域创建。

在这里，我们创建两个相同的 Amazon SQS 队列，其中一个用作死信队列：

 **导入**。

```
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.AmazonSQSException;
```

 **代码** 

```
final AmazonSQS sqs = AmazonSQSClientBuilder.defaultClient();

// Create source queue
try {
    sqs.createQueue(src_queue_name);
} catch (AmazonSQSException e) {
    if (!e.getErrorCode().equals("QueueAlreadyExists")) {
        throw e;
    }
}

// Create dead-letter queue
try {
    sqs.createQueue(dl_queue_name);
} catch (AmazonSQSException e) {
    if (!e.getErrorCode().equals("QueueAlreadyExists")) {
        throw e;
    }
}
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/DeadLetterQueues.java)。

## 为源队列指定死信队列
<a name="sqs-dead-letter-queue-set-redrive-policy"></a>

要指定死信队列，您必须先创建一个*重新驱动策略*，然后在队列属性中设置该策略。重新驱动策略以 JSON 指定，并指定死信队列的 ARN，以及在向死信队列发送消息之前，允许接收但不处理消息的最大次数。

要为源队列设置重新驱动策略，请使用 [SetQueueAttributesRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/sqs/model/SetQueueAttributesRequest.html) 对象调用 AmazonSQS 类的 `setQueueAttributes` 方法，并使用您的 JSON 重新驱动策略为该对象设置 `RedrivePolicy` 属性。

 **导入**。

```
import com.amazonaws.services.sqs.model.GetQueueAttributesRequest;
import com.amazonaws.services.sqs.model.GetQueueAttributesResult;
import com.amazonaws.services.sqs.model.SetQueueAttributesRequest;
```

 **代码** 

```
String dl_queue_url = sqs.getQueueUrl(dl_queue_name)
                         .getQueueUrl();

GetQueueAttributesResult queue_attrs = sqs.getQueueAttributes(
        new GetQueueAttributesRequest(dl_queue_url)
            .withAttributeNames("QueueArn"));

String dl_queue_arn = queue_attrs.getAttributes().get("QueueArn");

// Set dead letter queue with redrive policy on source queue.
String src_queue_url = sqs.getQueueUrl(src_queue_name)
                          .getQueueUrl();

SetQueueAttributesRequest request = new SetQueueAttributesRequest()
        .withQueueUrl(src_queue_url)
        .addAttributesEntry("RedrivePolicy",
                "{\"maxReceiveCount\":\"5\", \"deadLetterTargetArn\":\""
                + dl_queue_arn + "\"}");

sqs.setQueueAttributes(request);
```

请参阅 GitHub 上的[完整示例](https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/java/example_code/sqs/src/main/java/aws/example/sqs/DeadLetterQueues.java)。

## 更多信息
<a name="more-info"></a>
+  《Amazon SQS Developer Guide》中的 [Using Amazon SQS Dead Letter Queues](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)
+  《Amazon SQS API Reference》中的 [SetQueueAttributes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SetQueueAttributes.html)

# Amazon SWF使用 的 示例适用于 Java 的 AWS SDK
<a name="prog-services-swf"></a>

 [Amazon SWF](https://aws.amazon.com/swf/) 是一项工作流管理服务，可帮助开发人员构建和扩展分布式工作流，这些工作流可具有包含活动、子工作流或 [Lambda](https://aws.amazon.com/lambda/) 任务的并行或顺序步骤。

通过适用于 Java 的 AWS SDK 使用 Amazon SWF 有两种方法：使用 SWF *client* 对象或者使用适用于 Java 的 AWS Flow Framework。适用于 Java 的 AWS Flow Framework 的初始配置难度更大，因为它使用了大量批注并依赖其他库，例如 AspectJ 和 Spring Framework。但对于大型项目或复杂项目，您可使用适用于 Java 的 AWS Flow Framework 来节省编写代码的时间。有关更多信息，请参阅《[AWS Flow Framework for Java Developer Guide](https://docs.aws.amazon.com/amazonswf/latest/awsflowguide/)》。

此部分提供了直接使用Amazon SWF客户端来为 适用于 Java 的 AWS SDK 编程的示例。

**Topics**
+ [SWF 基本知识](swf-basics.md)
+ [构建简单 Amazon SWF 应用程序](swf-hello.md)
+ [Lambda 任务](swf-lambda-task.md)
+ [适当地关闭活动和工作流工作线程](swf-graceful-shutdown.md)
+ [注册域](prog-services-swf-register-domain.md)
+ [列出域](prog-services-swf-list-domains.md)

# SWF 基本知识
<a name="swf-basics"></a>

这些是通过 Amazon SWF 使用适用于 Java 的 AWS SDK的一般模式。这意味着它主要用于参考。有关更完整的介绍性教程，请参阅[构建简单 Amazon SWF 应用程序](swf-hello.md)。

## 依赖项
<a name="dependencies"></a>

基本 Amazon SWF 应用程序将需要适用于 Java 的 AWS SDK附带的以下依赖项：
+ aws-java-sdk-1.12.\$1.jar
+ commons-logging-1.2.\$1.jar
+ httpclient-4.3.\$1.jar
+ httpcore-4.3.\$1.jar
+ jackson-annotations-2.12.\$1.jar
+ jackson-core-2.12.\$1.jar
+ jackson-databind-2.12.\$1.jar
+ joda-time-2.8.\$1.jar

**注意**  
虽然这些程序包的版本号将因您拥有的 SDK 版本而异，但 SDK 附带的版本已经过兼容性测试，并且您应使用这些版本。

 适用于 Java 的 AWS Flow Framework 应用程序需要其他设置*和* 其他依赖项。有关使用框架的更多信息，请参阅《[AWS Flow Framework for Java Developer Guide](https://docs.aws.amazon.com/amazonswf/latest/awsflowguide/)》。

## 导入
<a name="imports"></a>

通常，您可以将以下导入用于代码开发：

```
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClientBuilder;
import com.amazonaws.services.simpleworkflow.model.*;
```

不过，好的做法是仅导入您所需的类。您可能最终会在 `com.amazonaws.services.simpleworkflow.model` 工作区中指定特定的类：

```
import com.amazonaws.services.simpleworkflow.model.PollForActivityTaskRequest;
import com.amazonaws.services.simpleworkflow.model.RespondActivityTaskCompletedRequest;
import com.amazonaws.services.simpleworkflow.model.RespondActivityTaskFailedRequest;
import com.amazonaws.services.simpleworkflow.model.TaskList;
```

如果您使用适用于 Java 的 AWS Flow Framework，则将从 `com.amazonaws.services.simpleworkflow.flow` 工作区导入类。例如：

```
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.flow.ActivityWorker;
```

**注意**  
除了适用于 Java 的 AWS SDK 的基本要求外，适用于 Java 的 AWS Flow Framework 还有额外要求。有关更多信息，请参阅《[AWS Flow Framework for Java Developer Guide](https://docs.aws.amazon.com/amazonswf/latest/awsflowguide/)》。

## 使用 SWF 客户端类
<a name="using-the-swf-client-class"></a>

您通过 Amazon SWFAmazonSimpleWorkflowClient[ 或 ](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/AmazonSimpleWorkflowClient.html)AmazonSimpleWorkflowAsyncClient[ 类与 ](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/AmazonSimpleWorkflowAsyncClient.html) 进行基本交互。二者之间的主要差异是，`\*AsyncClient` 类返回 [Future](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/Future.html) 对象以进行并发 (异步) 编程。

```
AmazonSimpleWorkflowClient swf = AmazonSimpleWorkflowClientBuilder.defaultClient();
```

# 构建简单 Amazon SWF 应用程序
<a name="swf-hello"></a>

此主题探讨如何使用适用于 Java 的 AWS SDK 编写 [Amazon SWF](https://aws.amazon.com/swf/) 应用程序，并在此过程中介绍了一些重要概念。

## 关于示例
<a name="about-the-example"></a>

示例项目将创建带有一个活动的工作流，接受通过 AWS Cloud 传递的工作流数据（在 HelloWorld 的传统中，这应该是要问候的某个人的名字）并在响应中打印问候语。

虽然表面上看起来这非常简单，不过 Amazon SWF 应用程序由多个协同工作的部件组成：
+ 一个**域**，用作工作流执行数据的逻辑容器。
+ 一个或多个**工作流程**，它们表示代码组件，这些组件定义工作流程的活动和子工作流程执行的逻辑顺序。
+ 一个**工作流工作线程**，也称为*决策程序*，轮询决策任务并在响应中计划活动或子工作流。
+ 一个或多个**活动**，每个活动表示工作流中的一个工作单元。
+ 一个**活动工作线程**，轮询活动任务并在响应中运行活动方法。
+ 一个或多个**任务列表**，这是由 Amazon SWF 维护的队列，用于发布请求到工作流和活动工作线程。任务列表上用于工作流工作线程的任务称为*决策任务*。用于活动工作线程的任务称为*活动任务*。
+ 一个**工作流启动程序**，用于开始工作流的执行。

在后台，Amazon SWF 协调这些组件的操作，协调从 AWS Cloud 的传输，在它们之间传递数据，处理超时和检测信号通知，以及记录工作流执行历史记录。

## 先决条件
<a name="prerequisitesswf"></a>

### 开发环境
<a name="development-environment"></a>

此教程中使用的开发环境包括：
+ -[适用于 Java 的 AWS SDK](https://aws.amazon.com/sdk-for-java/) 。
+  [Apache Maven](http://maven.apache.org/) (3.3.1)。
+ JDK 1.7 或更高版本。本教程使用 JDK 1.8.0 开发和测试。
+ 一个适用的 Java 文本编辑器 (由您选择)。

**注意**  
如果您使用的构建系统不是 Maven，则仍可以使用适用于您环境的相应步骤创建项目，并在这个过程中使用此处提供的概念。适用于 Java 的 AWS SDK入门[中提供了在不同编译系统中配置和使用 ](getting-started.md) 的更多信息。  
与此类似，但需要更多工作，此处列出的步骤也可以使用支持 Amazon SWF 的任意 AWS SDK 实施。

所有必需的外部依赖项包括在适用于 Java 的 AWS SDK 中，因此无需下载其他内容。

### AWS 访问
<a name="aws-access"></a>

要成功完成本教程，您必须有权访问 AWS 访问门户，如本指南的[基本设置部分所述](signup-create-iam-user.md#signup-create-iam-user-overview)。

这些说明描述了如何访问您复制并粘贴到本地共享 `credentials` 文件中的临时凭证。您粘贴的临时凭证必须与 AWS IAM Identity Center 中有权访问 Amazon SWF 的 IAM 角色关联。粘贴临时凭证后，您的 `credentials` 文件将类似于以下内容。

```
[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
aws_session_token=IQoJb3JpZ2luX2IQoJb3JpZ2luX2IQoJb3JpZ2luX2IQoJb3JpZ2luX2IQoJb3JpZVERYLONGSTRINGEXAMPLE
```

这些临时凭证与 `default` 配置文件相关联。

## 创建 SWF 项目
<a name="create-a-swf-project"></a>

1. 使用 Maven 启动新项目：

   ```
   mvn archetype:generate -DartifactId=helloswf \
   -DgroupId=aws.example.helloswf -DinteractiveMode=false
   ```

   这将创建具有标准 maven 项目结构的新项目：

   ```
   helloswf
   ├── pom.xml
   └── src
       ├── main
       │   └── java
       │       └── aws
       │           └── example
       │               └── helloswf
       │                   └── App.java
       └── test
           └── ...
   ```

   您可以忽略或删除 `test` 目录及其中包含的所有内容，我们不会将其用于此教程。您还可以删除 `App.java`，因为我们将使用新类来替换它。

1. 编辑项目的 `pom.xml` 文件，通过将 **aws-java-sdk-simpleworkflow** 模块的依赖项添加到 `<dependencies>` 块中来添加该模块。

   ```
   <dependencies>
     <dependency>
       <groupId>com.amazonaws</groupId>
       <artifactId>aws-java-sdk-simpleworkflow</artifactId>
       <version>1.11.1000</version>
     </dependency>
   </dependencies>
   ```

1.  *确保 Maven 使用 JDK 1.7\$1 支持构建您的项目*。将以下内容添加到您项目 (在 `<dependencies>` 块之前或之后) 的 `pom.xml` 中：

   ```
   <build>
     <plugins>
       <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>3.6.1</version>
         <configuration>
             <source>1.8</source>
             <target>1.8</target>
         </configuration>
       </plugin>
     </plugins>
   </build>
   ```

## 编码项目
<a name="code-the-project"></a>

示例项目包括四个独立的应用程序，我们将逐个查看：
+  **HelloTypes.java** -- 包含项目的域、活动和工作流类型数据，与其他组件共享。它还处理这些类型在 SWF 中的注册。
+  **ActivityWorker.java** -- 包含活动工作线程，将轮询活动任务并在响应中运行活动。
+  **WorkflowWorker.java** -- 包含工作流工作线程（决策程序），将轮询决策任务并计划新活动。
+  **WorkflowStarter.java** -- 包含工作流启动程序，将启动新的工作流执行，这将导致 SWF 开始生成决策和工作流任务供工作线程使用。

### 所有源文件的常见步骤
<a name="swf-hello-common"></a>

您创建的用于托管 Java 类的所有文件都有几个共同点。出于时间考虑，这些步骤*在每次添加新文件到项目时是隐含的*：

1. 在项目的 `src/main/java/aws/example/helloswf/` 目录中创建文件。

1. 添加 `package` 声明到每个文件的开头用于声明其命名空间。示例项目使用：

   ```
   package aws.example.helloswf;
   ```

1. 为 [AmazonSimpleWorkflowClient](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/AmazonSimpleWorkflowClient.html) 类和 `com.amazonaws.services.simpleworkflow.model` 命名空间中的多个类添加 `import` 声明。为了简化操作，我们使用：

   ```
   import com.amazonaws.regions.Regions;
   import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
   import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClientBuilder;
   import com.amazonaws.services.simpleworkflow.model.*;
   ```

### 注册域、工作流程和活动类型
<a name="swf-hello-hellotypes"></a>

我们将从创建新的可执行类 `HelloTypes.java` 开始。此文件将包含共享数据，您的工作流中的不同部分需要这些数据，例如活动的名称和版本以及工作流类型，域名和任务列表名称。

1. 打开文本编辑器并创建文件 `HelloTypes.java`，添加程序包声明并根据[通用步骤](#swf-hello-common)导入。

1. 声明 `HelloTypes` 类并向其提供值，以供注册的活动和工作流类型使用：

   ```
       public static final String DOMAIN = "HelloDomain";
       public static final String TASKLIST = "HelloTasklist";
       public static final String WORKFLOW = "HelloWorkflow";
       public static final String WORKFLOW_VERSION = "1.0";
       public static final String ACTIVITY = "HelloActivity";
       public static final String ACTIVITY_VERSION = "1.0";
   ```

   这些值将在代码中使用。

1. 在字符串声明之后，创建 [AmazonSimpleWorkflowClient](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/AmazonSimpleWorkflowClient.html) 类的实例。这是由Amazon SWF向 适用于 Java 的 AWS SDK 方法提供的基本接口。

   ```
   private static final AmazonSimpleWorkflow swf =
       AmazonSimpleWorkflowClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
   ```

   前面的代码片段假设临时凭证与 `default` 配置文件相关联。如果您使用其他配置文件，请按如下方式修改上面的代码，然后将 *profile\$1name* 替换为实际配置文件的名称。

   ```
   private static final AmazonSimpleWorkflow swf =
           AmazonSimpleWorkflowClientBuilder
                   .standard()
                   .withCredentials(new ProfileCredentialsProvider("profile_name"))
                   .withRegion(Regions.DEFAULT_REGION)
                   .build();
   ```

1. 添加新函数以注册到 SWF 域。*域* 是多种相关 SWF 活动和工作流类型的逻辑容器。SWF 组件只有在位于同一个域中时才能彼此通信。

   ```
       try {
           System.out.println("** Registering the domain '" + DOMAIN + "'.");
           swf.registerDomain(new RegisterDomainRequest()
               .withName(DOMAIN)
               .withWorkflowExecutionRetentionPeriodInDays("1"));
       } catch (DomainAlreadyExistsException e) {
           System.out.println("** Domain already exists!");
       }
   ```

   在注册域时，您需要提供*名称*（不含 `:`、`/`、`|`、控制字符或文本字符串“arn”的 1 至 256 个字符组合）以及*保留期*，这是在工作流执行完成后，Amazon SWF 保留工作流执行历史记录数据的天数。最长的工作流执行保留期为 90 天。有关更多信息，请参阅 [RegisterDomainRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/RegisterDomainRequest.html)。

   如果具有该名称的域已存在，则将引发 [DomainAlreadyExistsException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/DomainAlreadyExistsException.html)。因为我们并不关注是否已经创建了域，因此可以忽略此异常。
**注意**  
此代码演示了使用适用于 Java 的 AWS SDK方法时的一个通用模式，方法的数据由 `simpleworkflow.model` 命名空间中的类提供，该命名空间使用可链接的 `0with*` 方法实例化和填充。

1. 添加函数以注册新活动类型。*活动* 表示工作流中的一个工作单元。

   ```
       try {
           System.out.println("** Registering the activity type '" + ACTIVITY +
               "-" + ACTIVITY_VERSION + "'.");
           swf.registerActivityType(new RegisterActivityTypeRequest()
               .withDomain(DOMAIN)
               .withName(ACTIVITY)
               .withVersion(ACTIVITY_VERSION)
               .withDefaultTaskList(new TaskList().withName(TASKLIST))
               .withDefaultTaskScheduleToStartTimeout("30")
               .withDefaultTaskStartToCloseTimeout("600")
               .withDefaultTaskScheduleToCloseTimeout("630")
               .withDefaultTaskHeartbeatTimeout("10"));
       } catch (TypeAlreadyExistsException e) {
           System.out.println("** Activity type already exists!");
       }
   ```

   活动类型由*名称*和*版本*标识，它们在所注册到的域中用于将活动与任何其他活动区分开。活动还包含多种可选参数，例如用于从 SWF 接收任务和数据的默认任务列表，以及您可用来对活动各个部分执行所用时长施加限制的不同超时。有关更多信息，请参阅 [RegisterActivityTypeRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/RegisterActivityTypeRequest.html)。
**注意**  
所有超时值以*秒* 为单位指定。有关超时如何影响工作流执行的完整说明，请参阅 [Amazon SWF Timeout Types](https://docs.aws.amazon.com/amazonswf/latest/developerguide/swf-timeout-types.html)。

如果您尝试注册的活动类型已存在，则将引发 [TypeAlreadyExistsException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/TypeAlreadyExistsException.html)。添加函数以注册新工作流类型。*工作流程* 也称为*决策程序*，表示工作流程执行的逻辑。

\$1

```
    try {
        System.out.println("** Registering the workflow type '" + WORKFLOW +
            "-" + WORKFLOW_VERSION + "'.");
        swf.registerWorkflowType(new RegisterWorkflowTypeRequest()
            .withDomain(DOMAIN)
            .withName(WORKFLOW)
            .withVersion(WORKFLOW_VERSION)
            .withDefaultChildPolicy(ChildPolicy.TERMINATE)
            .withDefaultTaskList(new TaskList().withName(TASKLIST))
            .withDefaultTaskStartToCloseTimeout("30"));
    } catch (TypeAlreadyExistsException e) {
        System.out.println("** Workflow type already exists!");
    }
```

\$1

与活动类型类似，工作流类型由*名称* 和*版本* 标识，也具有可配置的超时。有关更多信息，请参阅 [RegisterWorkflowTypeRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/RegisterWorkflowTypeRequest.html)。

\$1

如果您尝试注册的工作流类型已存在，则将引发 [TypeAlreadyExistsException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/TypeAlreadyExistsException.html)。最后，请通过向类提供 `main` 方法确保其可执行，这反过来会注册域、活动类型和工作流类型：

\$1

```
    registerDomain();
    registerWorkflowType();
    registerActivityType();
```

现在，您可以[编译](#swf-hello-build)并[运行](#swf-hello-run-register)应用程序来运行注册脚本，或者继续对活动和工作流工作线程编写代码。注册了域、工作流和活动之后，您无需重新运行此步骤，这些内容将保留，直至您自行弃用它们。

### 实施活动工作线程
<a name="implement-the-activity-worker"></a>

*活动* 是工作流中的基本工作单元。工作流提供逻辑、要运行的计划活动 (或要采取的其他操作) 来响应决策任务。典型的工作流通常包含多种活动，可以同步、异步或者以两种方式结合运行。

*活动工作线程* 是一段代码，轮询由 Amazon SWF 生成的活动任务来响应工作流决策。在收到活动任务时，它将运行对应的活动并将成功/失败响应返回到工作流。

我们将实施驱动单个活动的简单活动工作线程。

1. 打开文本编辑器并创建文件 `ActivityWorker.java`，添加程序包声明并根据[通用步骤](#swf-hello-common)导入。

   ```
   import com.amazonaws.regions.Regions;
   import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
   import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClientBuilder;
   import com.amazonaws.services.simpleworkflow.model.*;
   ```

1. 向文件中添加 `ActivityWorker` 类，并向其提供数据成员以保存用来与 Amazon SWF 交互的 SWF 客户端：

   ```
       private static final AmazonSimpleWorkflow swf =
               AmazonSimpleWorkflowClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
   ```

1. 添加将用作活动的方法：

   ```
   private static String sayHello(String input) throws Throwable {
       return "Hello, " + input + "!";
   }
   ```

   该活动就是获取字符串，将其组合到问候语中，然后返回结果。虽然此活动有很小的可能性会引发异常，但最好的做法是将活动设计为在出现问题时会引发错误。

1. 添加我们将用作活动任务轮询方法的 `main` 方法。我们首先添加一些代码来轮询任务列表中的活动任务：

   ```
           System.out.println("Polling for an activity task from the tasklist '"
                   + HelloTypes.TASKLIST + "' in the domain '" +
                   HelloTypes.DOMAIN + "'.");
   
           ActivityTask task = swf.pollForActivityTask(
               new PollForActivityTaskRequest()
                   .withDomain(HelloTypes.DOMAIN)
                   .withTaskList(
                       new TaskList().withName(HelloTypes.TASKLIST)));
   
           String task_token = task.getTaskToken();
   ```

   活动通过调用 Amazon SWF 客户端的 `pollForActivityTask` 方法从 SWF 接收任务，指定在传入的 [PollForActivityTaskRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/PollForActivityTaskRequest.html) 中使用的域和任务列表。

   一旦收到任务，我们将通过调用任务的 `getTaskToken` 方法来检索它的唯一标识符。

1. 接下来，写入一些代码来处理传入的任务。将以下内容添加到您的 `main` 方法，就在轮询任务和检索其任务令牌代码的后方。

   ```
       if (task_token != null) {
           String result = null;
           Throwable error = null;
   
           try {
               System.out.println("Executing the activity task with input '" +
                       task.getInput() + "'.");
               result = sayHello(task.getInput());
           } catch (Throwable th) {
               error = th;
           }
   
           if (error == null) {
               System.out.println("The activity task succeeded with result '"
                       + result + "'.");
               swf.respondActivityTaskCompleted(
                   new RespondActivityTaskCompletedRequest()
                       .withTaskToken(task_token)
                       .withResult(result));
           } else {
               System.out.println("The activity task failed with the error '"
                       + error.getClass().getSimpleName() + "'.");
               swf.respondActivityTaskFailed(
                   new RespondActivityTaskFailedRequest()
                       .withTaskToken(task_token)
                       .withReason(error.getClass().getSimpleName())
                       .withDetails(error.getMessage()));
           }
       }
   ```

   如果任务令牌不是 `null`，则我们可以开始运行活动方法 (`sayHello`)，只要它具有随任务发送的输入数据。

   如果任务*成功*（未生成任何错误），则 worker 通过调用 SWF 客户端的 `respondActivityTaskCompleted` 方法来响应 SWF，该方法使用包含任务令牌和活动结果数据的 [RespondActivityTaskCompletedRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/RespondActivityTaskCompletedRequest.html) 对象。

   另一方面，如果任务*失败*，则我们通过调用带有 [RespondActivityTaskFailedRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/RespondActivityTaskFailedRequest.html) 对象的 `respondActivityTaskFailed` 方法进行响应，向其传递任务令牌和有关错误的信息。

**注意**  
如果终止，此活动不会正常关闭。虽然这超出了本教程的范围，不过在相关主题[适当地关闭活动和工作流工作线程](swf-graceful-shutdown.md)中提供了此活动工作线程的替代实施方法。

### 实施工作流工作线程
<a name="implement-the-workflow-worker"></a>

您的工作流逻辑位于称为**工作流工作线程**的代码块中。工作流工作线程在工作流类型注册到的默认任务列表上，轮询域中 Amazon SWF 发送的决策任务。

工作流工作线程接收任务时，它会做出某种类型的决策 (通常为是否计划新活动) 并采取相应操作 (例如计划活动)。

1. 打开文本编辑器并创建文件 `WorkflowWorker.java`，添加程序包声明并根据[通用步骤](#swf-hello-common)导入。

1. 将一些额外的导入添加到文件中：

   ```
   import com.amazonaws.regions.Regions;
   import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
   import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClientBuilder;
   import com.amazonaws.services.simpleworkflow.model.*;
   import java.util.ArrayList;
   import java.util.List;
   import java.util.UUID;
   ```

1. 声明 `WorkflowWorker` 类，创建用于访问 SWF 方法的 [AmazonSimpleWorkflowClient](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/AmazonSimpleWorkflowClient.html) 类的实例。

   ```
       private static final AmazonSimpleWorkflow swf =
               AmazonSimpleWorkflowClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
   ```

1. 添加 `main` 方法。该方法持续循环，使用 SWF 客户端的 `pollForDecisionTask` 方法轮询决策任务。[PollForDecisionTaskRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/PollForDecisionTaskRequest.html) 提供详细信息。

   ```
       PollForDecisionTaskRequest task_request =
           new PollForDecisionTaskRequest()
               .withDomain(HelloTypes.DOMAIN)
               .withTaskList(new TaskList().withName(HelloTypes.TASKLIST));
   
       while (true) {
           System.out.println(
                   "Polling for a decision task from the tasklist '" +
                   HelloTypes.TASKLIST + "' in the domain '" +
                   HelloTypes.DOMAIN + "'.");
   
           DecisionTask task = swf.pollForDecisionTask(task_request);
   
           String taskToken = task.getTaskToken();
           if (taskToken != null) {
               try {
                   executeDecisionTask(taskToken, task.getEvents());
               } catch (Throwable th) {
                   th.printStackTrace();
               }
           }
       }
   ```

   在收到任务之后，我们调用其 `getTaskToken` 方法，这会返回可用于标识任务的字符串。如果返回的令牌不是 `null`，则我们在 `executeDecisionTask` 方法中进一步处理它，向它传递随任务发送的任务令牌以及 [HistoryEvent](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/HistoryEvent.html) 对象的列表。

1. 添加 `executeDecisionTask` 方法，获取任务令牌 (`String`) 和 `HistoryEvent` 列表。

   ```
       List<Decision> decisions = new ArrayList<Decision>();
       String workflow_input = null;
       int scheduled_activities = 0;
       int open_activities = 0;
       boolean activity_completed = false;
       String result = null;
   ```

   我们还可以设置一些数据成员来跟踪内容，例如：
   + 用于报告任务处理结果的[决策](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/Decision.html)对象列表。
   + 用于保存由“WorkflowExecutionStarted”事件提供的工作流输入的字符串
   + 已计划和打开 (正在运行) 活动的计数，用于避免再次计划已经计划或者当前正在运行的相同活动。
   + 用于指示活动已完成的布尔值。
   + 用于保存活动结果的字符串，以将其作为我们的工作流结果返回。

1. 接下来，添加一些代码到 `executeDecisionTask`，基于 `HistoryEvent` 方法报告的事件类型处理随任务发送的 `getEventType` 对象。

   ```
   System.out.println("Executing the decision task for the history events: [");
   for (HistoryEvent event : events) {
       System.out.println("  " + event);
       switch(event.getEventType()) {
           case "WorkflowExecutionStarted":
               workflow_input =
                   event.getWorkflowExecutionStartedEventAttributes()
                        .getInput();
               break;
           case "ActivityTaskScheduled":
               scheduled_activities++;
               break;
           case "ScheduleActivityTaskFailed":
               scheduled_activities--;
               break;
           case "ActivityTaskStarted":
               scheduled_activities--;
               open_activities++;
               break;
           case "ActivityTaskCompleted":
               open_activities--;
               activity_completed = true;
               result = event.getActivityTaskCompletedEventAttributes()
                             .getResult();
               break;
           case "ActivityTaskFailed":
               open_activities--;
               break;
           case "ActivityTaskTimedOut":
               open_activities--;
               break;
       }
   }
   System.out.println("]");
   ```

   对于我们的工作流，我们最感兴趣的是：
   + “WorkflowExecutionStarted”事件，这指示工作流执行已启动 (通常意味着您应该运行工作流中的第一个活动)，并且这提供了初始输入 (提供到工作流中)。在这种情况下，这是我们问候语的名称部分，因此将其保存在字符串中以在计划活动运行时使用。
   + “ActivityTaskCompleted”事件在计划的活动完成后立即发送。事件数据还包括已完成活动的返回值。因为我们仅有一个活动，我们将使用该值作为整个工作流程的结果。

   其他事件类型在工作流需要时可以使用。有关各个事件类型的信息，请参阅 [HistoryEvent](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/HistoryEvent.html) 类说明。

   \$1 注意：`switch` 语句中的字符串在 Java 7 中引入。如果您使用的是 Java 的较早版本，则可以使用 [EventType](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/model/EventType.html) 类将 `history_event.getType()` 返回的 `String` 转换为枚举值，然后可在需要时将其转换回 `String`：

```
EventType et = EventType.fromValue(event.getEventType());
```

1. 在 `switch` 语句之后，添加更多代码，根据所收到的任务采用合适的*决策* 进行响应。

   ```
   if (activity_completed) {
       decisions.add(
           new Decision()
               .withDecisionType(DecisionType.CompleteWorkflowExecution)
               .withCompleteWorkflowExecutionDecisionAttributes(
                   new CompleteWorkflowExecutionDecisionAttributes()
                       .withResult(result)));
   } else {
       if (open_activities == 0 && scheduled_activities == 0) {
   
           ScheduleActivityTaskDecisionAttributes attrs =
               new ScheduleActivityTaskDecisionAttributes()
                   .withActivityType(new ActivityType()
                       .withName(HelloTypes.ACTIVITY)
                       .withVersion(HelloTypes.ACTIVITY_VERSION))
                   .withActivityId(UUID.randomUUID().toString())
                   .withInput(workflow_input);
   
           decisions.add(
                   new Decision()
                       .withDecisionType(DecisionType.ScheduleActivityTask)
                       .withScheduleActivityTaskDecisionAttributes(attrs));
       } else {
           // an instance of HelloActivity is already scheduled or running. Do nothing, another
           // task will be scheduled once the activity completes, fails or times out
       }
   }
   
   System.out.println("Exiting the decision task with the decisions " + decisions);
   ```
   + 如果尚未计划活动，我们使用 `ScheduleActivityTask` 决策进行响应，这在 [ScheduleActivityTaskDecisionAttributes](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/ScheduleActivityTaskDecisionAttributes.html) 结构中提供关于 Amazon SWF 接下来应计划的活动的信息，也包括 Amazon SWF 应发送到活动的任何数据。
   + 如果活动已完成，则我们将考虑完成的整个工作流，并使用 `CompletedWorkflowExecution` 决策进行响应，填入 [CompleteWorkflowExecutionDecisionAttributes](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/CompleteWorkflowExecutionDecisionAttributes.html) 结构以提供有关已完成工作流的详细信息。在这种情况下，我们将返回活动的结果。

   在任何一种情况下，决策信息将添加到在方法顶部声明的 `Decision` 列表。

1. 返回在处理任务时收集的 `Decision` 对象列表来完成决策任务。在我们所编写的 `executeDecisionTask` 方法尾部添加此代码：

   ```
   swf.respondDecisionTaskCompleted(
       new RespondDecisionTaskCompletedRequest()
           .withTaskToken(taskToken)
           .withDecisions(decisions));
   ```

   SWF 客户端的 `respondDecisionTaskCompleted` 方法获取标识任务的任务令牌以及 `Decision` 对象列表。

### 实施工作流启动程序
<a name="implement-the-workflow-starter"></a>

最后，我们将编写一些代码用于启动工作流程执行。

1. 打开文本编辑器并创建文件 `WorkflowStarter.java`，添加程序包声明并根据[通用步骤](#swf-hello-common)导入。

1. 添加 `WorkflowStarter` 类：

   ```
   package aws.example.helloswf;
   
   
   import com.amazonaws.regions.Regions;
   import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
   import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClientBuilder;
   import com.amazonaws.services.simpleworkflow.model.*;
   
   public class WorkflowStarter {
       private static final AmazonSimpleWorkflow swf =
               AmazonSimpleWorkflowClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
       public static final String WORKFLOW_EXECUTION = "HelloWorldWorkflowExecution";
   
       public static void main(String[] args) {
           String workflow_input = "{SWF}";
           if (args.length > 0) {
               workflow_input = args[0];
           }
   
           System.out.println("Starting the workflow execution '" + WORKFLOW_EXECUTION +
                   "' with input '" + workflow_input + "'.");
   
           WorkflowType wf_type = new WorkflowType()
               .withName(HelloTypes.WORKFLOW)
               .withVersion(HelloTypes.WORKFLOW_VERSION);
   
           Run run = swf.startWorkflowExecution(new StartWorkflowExecutionRequest()
               .withDomain(HelloTypes.DOMAIN)
               .withWorkflowType(wf_type)
               .withWorkflowId(WORKFLOW_EXECUTION)
               .withInput(workflow_input)
               .withExecutionStartToCloseTimeout("90"));
   
           System.out.println("Workflow execution started with the run id '" +
                   run.getRunId() + "'.");
       }
   }
   ```

   `WorkflowStarter` 类包含一个方法 `main`，它获取命令行上传递的可选参数作为工作流的输入数据。

   SWF 客户端方法 `startWorkflowExecution`，获取 [StartWorkflowExecutionRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/StartWorkflowExecutionRequest.html) 对象作为输入。此处，除了指定要运行的域和工作流类型之外，我们提供了：
   + 便于阅读的工作流执行名称
   + 工作流输入数据 (我们的示例中在命令行上提供)
   + 超时值，以秒为单位，表示整个工作流运行所应使用的时长。

   [ 返回的](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/Run.html)运行`startWorkflowExecution`对象提供了*运行 ID*，这是用于在 Amazon SWF 的工作流执行历史记录中标识此特定工作流执行的值。

   \$1 注意：运行 ID 由 Amazon SWF 生成，*不同于* 您在启动工作流执行时传入的工作流执行名称。

## 编译示例
<a name="swf-hello-build"></a>

要使用 Maven 编译示例项目，请转到 `helloswf` 目录并键入：

```
mvn package
```

生成的 `helloswf-1.0.jar` 将在 `target` 目录中生成。

## 运行示例
<a name="run-the-example"></a>

示例包括四个独立的可执行类，彼此独立运行。

**注意**  
如果您使用的是 Linux、macOS 或 Unix 系统，您可以在单个终端窗口中将它们全部逐个运行。如果您运行的是 Windows，则应该打开两个额外的命令行实例并分别导航到 `helloswf` 目录。

### 设置 Java 类路径
<a name="swf-hello-set-classpath"></a>

虽然 Maven 已经为您处理了依赖项来运行示例，您仍需要在 Java 类路径上提供 AWS SDK 库及其依赖项。您可以将 `CLASSPATH` 环境变量设置为 AWS SDK 库的位置，以及 SDK 中包括必要依赖项的 `third-party/lib` 目录：

```
export CLASSPATH='target/helloswf-1.0.jar:/path/to/sdk/lib/*:/path/to/sdk/third-party/lib/*'
java example.swf.hello.HelloTypes
```

或者使用 **` java `** 命令的 `-cp` 选项在运行各个应用程序时设置类路径。

```
java -cp target/helloswf-1.0.jar:/path/to/sdk/lib/*:/path/to/sdk/third-party/lib/* \
  example.swf.hello.HelloTypes
```

您使用的样式由您决定。如果您在编译代码时没有问题，但在尝试运行示例时遇到一系列“NoClassDefFound”错误，则可能是因为类路径设置不正确。

### 注册域、工作流程和活动类型
<a name="swf-hello-run-register"></a>

在运行工作线程和工作流程启动程序之前，您需要注册域以及工作流程和活动类型。执行此操作的代码在[注册域、工作流和活动类型](#swf-hello-hellotypes)中实施。

在编译之后，如果您已[设置 CLASSPATH](#swf-hello-set-classpath)，则可以通过执行以下命令运行注册代码：

```
    echo 'Supply the name of one of the example classes as an argument.'
```

### 启动活动和工作流工作线程
<a name="swf-hello-run-workers"></a>

现在类型已注册，您可以启动活动和工作流工作线程。它们将持续运行并轮询任务，直至终止，因此您应该在单独终端窗口中运行它们，或者，如果您在 Linux、macOS 或 Unix 上运行它们，则可以使用 `&` 运算符来使得它们中的每一个在运行时生成单独进程。

```
    echo 'If there are arguments to the class, put them in quotes after the class name.'
    exit 1
```

如果您在单独窗口中运行这些命令，则忽略每一行最后的 `&` 运算符。

### 启动工作流执行
<a name="swf-hello-start-execution"></a>

现在正在轮询您的活动和工作流工作线程，您可以启动工作流执行。此进程将运行直至工作流返回已完成状态。您应在新终端窗口中运行它 (除非您使用 `&` 运算符将工作线程作为新生成的进程运行)。

```
fi
```

**注意**  
如果您要提供自己的输入数据 (这将首先传递到工作流，然后传递到活动)，则将其添加到命令行中。例如：  

```
echo "## Running $className..."
```

一旦开始工作流执行，您应该开始查看这两种工作线程以及工作流执行本身提供的输出。工作流最终完成之后，其输出将显示在屏幕上。

## 此示例的完整源代码
<a name="complete-source-for-this-example"></a>

您可以在 Github 的 [aws-java-developer-guide](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/java/example_code/swf) 存储库中浏览此示例的*完整源代码*。

## 有关更多信息
<a name="for-more-information"></a>
+ 如果在工作流轮询仍在进行时关闭此处提供的工作线程，则它们会导致任务丢失。要了解如何适当地关闭工作线程，请参阅[适当地关闭活动和工作流工作线程](swf-graceful-shutdown.md)。
+ 如需了解有关 Amazon SWF 的更多信息，请访问 [Amazon SWF](https://aws.amazon.com/swf/) 主页或查看《[Amazon SWF Developer Guide](https://docs.aws.amazon.com/amazonswf/latest/developerguide/)》。
+ 您可以使用适用于 Java 的 AWS Flow Framework，使用注释以更讲究的 Java 样式编写更复杂的工作流。如需了解更多信息，请参阅《[AWS Flow Framework for Java Developer Guide](https://docs.aws.amazon.com/amazonswf/latest/awsflowguide/)》。

# Lambda 任务
<a name="swf-lambda-task"></a>

另一个方法是与 Amazon SWF 活动一起使用，就是使用 [Lambda](https://aws.amazon.com/lambda/) 函数代表工作流中的工作单元，并按照安排活动的相似方法安排它们。

本主题主要介绍如何使用适用于 Java 的 AWS SDK 实施 Amazon SWF Lambda 任务。有关 Lambda 任务的更多一般性信息，请参阅《Amazon SWF Developer Guide》中的 [AWS Lambda Tasks](https://docs.aws.amazon.com/amazonswf/latest/developerguide/lambda-task.html)。

## 设置跨服务 IAM 角色以运行 Lambda 函数
<a name="set-up-a-cross-service-iam-role-to-run-your-lambda-function"></a>

在 Amazon SWF 能够运行您的 Lambda 函数前，需要设置一个 IAM 角色，授予让它代表您运行 Lambda 函数的 Amazon SWF 权限。有关如何完成该操作的完整信息，请参阅 [AWS Lambda Tasks](https://docs.aws.amazon.com/amazonswf/latest/developerguide/lambda-task.html)。

在注册将使用 Lambda 任务的工作流时，将需要此 IAM 角色的 Amazon 资源名称 (ARN)。

## 创建 Lambda 函数
<a name="create-a-lambda-function"></a>

您可以使用包括 Java 在内的多种不同语言编写 Lambda 函数。有关如何编写、部署和使用 Lambda 函数的完整信息，请参阅《[AWS Lambda 开发人员指南](https://docs.aws.amazon.com/lambda/latest/dg/)》。

**注意**  
使用哪种语言编写 Lambda 函数并不重要，无论使用哪种语言编写工作流代码，*所有* Amazon SWF 工作流都可以安排和运行您的函数。Amazon SWF 处理运行函数和传入传出数据的详细信息。

下面是一个简单的 Lambda 函数，它可以用于代替[构建简单 Amazon SWF 应用程序](swf-hello.md)中的活动。
+ 该版本使用 JavaScript 编写，使用 [AWS 管理控制台](https://console.aws.amazon.com/console/home)可以直接输入。

  ```
  exports.handler = function(event, context) {
      context.succeed("Hello, " + event.who + "!");
  };
  ```
+ 以下是使用 Java 编写的相同函数，您同样可以在 Lambda 上部署和运行它：

  ```
  package example.swf.hellolambda;
  
  import com.amazonaws.services.lambda.runtime.Context;
  import com.amazonaws.services.lambda.runtime.RequestHandler;
  import com.amazonaws.util.json.JSONException;
  import com.amazonaws.util.json.JSONObject;
  
  public class SwfHelloLambdaFunction implements RequestHandler<Object, Object> {
      @Override
      public Object handleRequest(Object input, Context context) {
          String who = "{SWF}";
          if (input != null) {
              JSONObject jso = null;
              try {
                  jso = new JSONObject(input.toString());
                  who = jso.getString("who");
              } catch (JSONException e) {
                  e.printStackTrace();
              }
          }
          return ("Hello, " + who + "!");
      }
  }
  ```
**注意**  
要了解有关将 Java 函数部署到 Lambda 的更多信息，请参阅《AWS Lambda 开发人员指南》中的[创建部署包 (Java)](https://docs.aws.amazon.com/lambda/latest/dg/lambda-java-how-to-create-deployment-package.html)。您可能还希望查看标题为[使用 Java 编写 Lambda 函数的编程模型](https://docs.aws.amazon.com/lambda/latest/dg/java-programming-model.html)的章节。

 Lambda 函数使用 *event* 或 *input* 对象作为第一个参数，使用 *context* 对象作为第二个参数，提供有关运行 Lambda 函数的请求的相关信息。该特定函数要求使用 JSON 提供输入，并将 `who` 字段设置为用于创建问候语的名称。

## 注册用于 Lambda 的工作流
<a name="register-a-workflow-for-use-with-lam"></a>

对于预定 Lambda 函数的工作流，必须提供 IAM 角色的名称，由其为 Amazon SWF 提供调用 Lambda 函数的权限。您可以在工作流注册期间，使用 `withDefaultLambdaRole`RegisterWorkflowTypeRequest`setDefaultLambdaRole` 的 [ 或 ](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/RegisterWorkflowTypeRequest.html) 方法完成该设置。

```
System.out.println("** Registering the workflow type '" + WORKFLOW + "-" + WORKFLOW_VERSION
        + "'.");
try {
    swf.registerWorkflowType(new RegisterWorkflowTypeRequest()
        .withDomain(DOMAIN)
        .withName(WORKFLOW)
        .withDefaultLambdaRole(lambda_role_arn)
        .withVersion(WORKFLOW_VERSION)
        .withDefaultChildPolicy(ChildPolicy.TERMINATE)
        .withDefaultTaskList(new TaskList().withName(TASKLIST))
        .withDefaultTaskStartToCloseTimeout("30"));
}
catch (TypeAlreadyExistsException e) {
```

## 调度 Lambda 任务
<a name="schedule-a-lam-task"></a>

调度 Lambda 任务与调度活动相似。您提供一条[决策](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/Decision.html)，该决策具有“ScheduleLambdaFunction”[DecisionType](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/DecisionType.html) 和 [ScheduleLambdaFunctionDecisionAttributes](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/ScheduleLambdaFunctionDecisionAttributes.html)。

```
running_functions == 0 && scheduled_functions == 0) {
AWSLambda lam = AWSLambdaClientBuilder.defaultClient();
GetFunctionConfigurationResult function_config =
    lam.getFunctionConfiguration(
            new GetFunctionConfigurationRequest()
                .withFunctionName("HelloFunction"));
String function_arn = function_config.getFunctionArn();

ScheduleLambdaFunctionDecisionAttributes attrs =
    new ScheduleLambdaFunctionDecisionAttributes()
        .withId("HelloFunction (Lambda task example)")
        .withName(function_arn)
        .withInput(workflow_input);

decisions.add(
```

在 `ScheduleLambdaFuntionDecisionAttributes` 中，必须提供 *name*，这是要调用的 Lambda 函数的 ARN；还必须提供 *id*，这是 Amazon SWF 用于在历史记录日志中标识 Lambda 函数的名称。

还可以为 Lambda 函数提供可选的 *input* 并设置其 *start to close timeout* 值，这是在生成 `LambdaFunctionTimedOut` 事件之前允许 Lambda 函数运行的秒数。

**注意**  
在给出函数名称后，该代码使用 [AWSLambdaClient](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/lambda/AWSLambdaClient.html) 检索 Lambda 函数的 ARN。您可以使用该方法，以避免您的代码中包含完整 ARN 的硬编码（包括 AWS 账户 ID）。

## 在决策程序中处理 Lambda 函数事件
<a name="handle-lam-function-events-in-your-decider"></a>

 Lambda 任务会使用 LambdaEventType[ 值 (如 ](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/EventType.html)、`LambdaFunctionScheduled` 和 `LambdaFunctionStarted`) 生成与 `LambdaFunctionCompleted` 任务生命周期对应的多个事件，在工作流工作线程中轮询决策任务时可以对这些事件执行操作。如果 Lambda 函数失败或运行时间超出其超时值，您会分别收到 `LambdaFunctionFailed` 或 `LambdaFunctionTimedOut` 事件类型。

```
boolean function_completed = false;
String result = null;

System.out.println("Executing the decision task for the history events: [");
for (HistoryEvent event : events) {
    System.out.println("  " + event);
    EventType event_type = EventType.fromValue(event.getEventType());
    switch(event_type) {
    case WorkflowExecutionStarted:
        workflow_input =
            event.getWorkflowExecutionStartedEventAttributes()
                 .getInput();
        break;
    case LambdaFunctionScheduled:
        scheduled_functions++;
        break;
    case ScheduleLambdaFunctionFailed:
        scheduled_functions--;
        break;
    case LambdaFunctionStarted:
        scheduled_functions--;
        running_functions++;
        break;
    case LambdaFunctionCompleted:
        running_functions--;
        function_completed = true;
        result = event.getLambdaFunctionCompletedEventAttributes()
                      .getResult();
        break;
    case LambdaFunctionFailed:
        running_functions--;
        break;
    case LambdaFunctionTimedOut:
        running_functions--;
        break;
```

## 从您的 Lambda 函数接收输出
<a name="receive-output-from-your-lam-function"></a>

在 [HistoryEvent](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/HistoryEvent.html) 上接收 `LambdaFunctionCompleted`[EventType](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/EventType.html), you can retrieve your 0 function’s return value by first calling `getLambdaFunctionCompletedEventAttributes` 时，以获取 [LambdaFunctionCompletedEventAttributes](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/LambdaFunctionCompletedEventAttributes.html) 对象，然后调用其 `getResult` 方法以检索 Lambda 函数的输出：

```
 LambdaFunctionCompleted:
running_functions--;
```

## 此示例的完整源代码
<a name="complete-source-for-this-example"></a>

您可以在 Github 上的 *aws-java-developer-guide* 存储库中，浏览 *complete source :github:`<awsdocs/aws-java-developer-guide/tree/master/doc\$1source/snippets/helloswf\$1lambda/>*，以查看此示例。

# 适当地关闭活动和工作流工作线程
<a name="swf-graceful-shutdown"></a>

[构建简单 Amazon SWF 应用程序](swf-hello.md)主题中介绍实施包括注册应用程序、活动、工作流工作线程以及工作流启动程序的简单工作流应用程序的整个过程。

工作线程类设计为持续运行，轮询 Amazon SWF 发送的任务，以便运行活动或返回决策。完成轮询请求后，Amazon SWF 会记录轮询器，并尝试为其分配任务。

如果工作流工作线程在长轮询过程中终止，Amazon SWF 可能仍然会尝试向终止的工作线程发送任务，导致该任务丢失 (直至该任务超时)。

解决上述情况的一个方法是等待所有长轮询请求返回，然后再终止工作线程。

在该主题中，我们会使用 Java 的关闭挂钩来重写 `helloswf` 中的活动工作线程，以尝试适当地关闭活动工作线程。

以下是完整的代码：

```
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import com.amazonaws.regions.Regions;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClientBuilder;
import com.amazonaws.services.simpleworkflow.model.ActivityTask;
import com.amazonaws.services.simpleworkflow.model.PollForActivityTaskRequest;
import com.amazonaws.services.simpleworkflow.model.RespondActivityTaskCompletedRequest;
import com.amazonaws.services.simpleworkflow.model.RespondActivityTaskFailedRequest;
import com.amazonaws.services.simpleworkflow.model.TaskList;

public class ActivityWorkerWithGracefulShutdown {

    private static final AmazonSimpleWorkflow swf =
        AmazonSimpleWorkflowClientBuilder.standard().withRegion(Regions.DEFAULT_REGION).build();
    private static final CountDownLatch waitForTermination = new CountDownLatch(1);
    private static volatile boolean terminate = false;

    private static String executeActivityTask(String input) throws Throwable {
        return "Hello, " + input + "!";
    }

    public static void main(String[] args) {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try {
                    terminate = true;
                    System.out.println("Waiting for the current poll request" +
                            " to return before shutting down.");
                    waitForTermination.await(60, TimeUnit.SECONDS);
                }
                catch (InterruptedException e) {
                    // ignore
                }
            }
        });
        try {
            pollAndExecute();
        }
        finally {
            waitForTermination.countDown();
        }
    }

    public static void pollAndExecute() {
        while (!terminate) {
            System.out.println("Polling for an activity task from the tasklist '"
                    + HelloTypes.TASKLIST + "' in the domain '" +
                    HelloTypes.DOMAIN + "'.");

            ActivityTask task = swf.pollForActivityTask(new PollForActivityTaskRequest()
                .withDomain(HelloTypes.DOMAIN)
                .withTaskList(new TaskList().withName(HelloTypes.TASKLIST)));

            String taskToken = task.getTaskToken();

            if (taskToken != null) {
                String result = null;
                Throwable error = null;

                try {
                    System.out.println("Executing the activity task with input '"
                            + task.getInput() + "'.");
                    result = executeActivityTask(task.getInput());
                }
                catch (Throwable th) {
                    error = th;
                }

                if (error == null) {
                    System.out.println("The activity task succeeded with result '"
                            + result + "'.");
                    swf.respondActivityTaskCompleted(
                        new RespondActivityTaskCompletedRequest()
                            .withTaskToken(taskToken)
                            .withResult(result));
                }
                else {
                    System.out.println("The activity task failed with the error '"
                            + error.getClass().getSimpleName() + "'.");
                    swf.respondActivityTaskFailed(
                        new RespondActivityTaskFailedRequest()
                            .withTaskToken(taskToken)
                            .withReason(error.getClass().getSimpleName())
                            .withDetails(error.getMessage()));
                }
            }
        }
    }
}
```

在该版本中，原始版本的 `main` 功能中的轮询代码已被移至其自己的 `pollAndExecute` 方法中。

现在，`main` 功能使用 [CountDownLatch](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/CountDownLatch.html) 以及[关闭挂钩](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/Runtime.html)，实现了在收到终止线程的请求后，让线程等待最多 60 秒才允许线程关闭。

# 注册域
<a name="prog-services-swf-register-domain"></a>

[Amazon SWF](https://aws.amazon.com/swf/) 中的每个工作流和活动均需包含一个*域*，以在其中运行。

1. 创建新的 [RegisterDomainRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/RegisterDomainRequest.html) 对象，并至少为该对象提供域名和工作流执行保留期 (这两个参数是必需的)。

1. 使用 *RegisterDomainRequest* 对象调用 [AmazonSimpleWorkflowClient.registerDomain](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/AmazonSimpleWorkflowClient.html#registerDomain-com.amazonaws.services.simpleworkflow.model.RegisterDomainRequest-) 方法。

1. 如果您请求的域已存在（在此情况下，通常不需要任何操作），则将捕获 [DomainAlreadyExistsException](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/DomainAlreadyExistsException.html)。

以下代码演示了此过程：

```
public void register_swf_domain(AmazonSimpleWorkflowClient swf, String name)
{
    RegisterDomainRequest request = new RegisterDomainRequest().withName(name);
    request.setWorkflowExecutionRetentionPeriodInDays("10");
    try
    {
        swf.registerDomain(request);
    }
    catch (DomainAlreadyExistsException e)
    {
        System.out.println("Domain already exists!");
    }
}
```

# 列出域
<a name="prog-services-swf-list-domains"></a>

您可以按照注册类型，列出与账户和 AWS 区域关联的 [Amazon SWF](https://aws.amazon.com/swf/) 域。

1. 创建 [ListDomainsRequest](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/ListDomainsRequest.html) 对象，然后指定目标域的注册状态（必填项）。

1. 使用 *ListDomainRequest* 对象调用 [AmazonSimpleWorkflowClient.listDomains](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/AmazonSimpleWorkflowClient.html#listDomains-com.amazonaws.services.simpleworkflow.model.ListDomainsRequest-)。结果在 [DomainInfos](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/DomainInfos.html) 对象中提供。

1. 对返回的对象调用 [getDomainInfos](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/DomainInfos.html#getDomainInfos--)，以获取 [DomainInfo](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/DomainInfo.html) 对象的列表。

1. 在每个 *DomainInfo* 对象上调用 [getName](https://docs.aws.amazon.com/sdk-for-java/v1/reference/com/amazonaws/services/simpleworkflow/model/DomainInfo.html#getName--) 来获取其名称。

以下代码演示了此过程：

```
public void list_swf_domains(AmazonSimpleWorkflowClient swf)
{
    ListDomainsRequest request = new ListDomainsRequest();
    request.setRegistrationStatus("REGISTERED");
    DomainInfos domains = swf.listDomains(request);
    System.out.println("Current Domains:");
    for (DomainInfo di : domains.getDomainInfos())
    {
        System.out.println(" * " + di.getName());
    }
}
```

# SDK 中包含的代码示例
<a name="java-dg-samples"></a>

适用于 Java 的 AWS SDK 附带代码示例，这些示例在可构建且可运行的程序中演示了该开发工具包的许多功能。您可以学习或修改这些程序，以使用适用于 Java 的 AWS SDK 实现您自己的 AWS 解决方案。

## 如何获取示例
<a name="how-to-get-the-samples"></a>

适用于 Java 的 AWS SDK代码示例在开发工具包的 *samples* 目录中提供。如果您已使用[设置适用于 Java 的 AWS SDK](setup-install.md) 中的信息下载并安装 SDK，则您的系统中已包含示例。

您也可以在适用于 Java 的 AWS SDK GitHub 存储库中查看最新示例（位于 [src/samples](https://github.com/aws/aws-sdk-java/tree/master/src/samples) 目录中）。

## 使用命令行构建并运行示例
<a name="samples-cmdline"></a>

示例包含 [Ant](http://ant.apache.org/) 构建脚本，以便您从命令行轻松构建和运行这些脚本。每个示例还包含一个 HTML 格式的 README 文件，此文件包含每个示例特定的信息。

**注意**  
如果您浏览 GitHub 上的代码示例，请在查看示例的 README.html 文件时单击源代码显示中的 **Raw (原始)** 按钮。在原始模式中，HTML 将在浏览器中按预期方式呈现。

### 先决条件
<a name="prerequisitessamples"></a>

在运行任何适用于 Java 的 AWS SDK 示例之前，您需要在环境中或使用 AWS CLI 设置 AWS 凭证，如[设置用于开发的 AWS 凭证和区域](setup-credentials.md)中所述。这些示例使用默认凭证提供程序链 (如果可能)。因此，您可以通过此方式设置凭证以消除将 AWS 凭证插入源代码目录中的文件（可能无意中签入并公开共享这些凭证）的有风险的实践。

### 运行示例
<a name="running-the-samples"></a>

1. 对包含示例代码的目录所做的更改。例如，如果您在 AWS SDK 下载的根目录中，并且希望运行 `AwsConsoleApp` 示例，则可键入：

   ```
   cd samples/AwsConsoleApp
   ```

1. 使用 Ant 构建和运行示例。默认构建目标将执行这两项操作，您只需输入：

   ```
   ant
   ```

该示例将信息打印到标准输出，例如：

```
===========================================

Welcome to the {AWS} Java SDK!

===========================================
You have access to 4 Availability Zones.

You have 0 {EC2} instance(s) running.

You have 13 Amazon SimpleDB domain(s) containing a total of 62 items.

You have 23 {S3} bucket(s), containing 44 objects with a total size of 154767691 bytes.
```

## 使用 Eclipse IDE 构建并运行示例
<a name="building-and-running-the-samples-using-the-eclipse-ide"></a>

如果您使用 AWS Toolkit for Eclipse，也可以基于适用于 Java 的 AWS SDK在 Eclipse 中启动新项目或将该开发工具包添加到现有 Java 项目。

### 先决条件
<a name="id1samples"></a>

在安装 AWS Toolkit for Eclipse 后，建议您使用安全凭证配置此工具包。您可以随时通过以下方式执行此操作：从 Eclipse 中的**窗口**菜单选择**首选项**，然后选择 **AWS Toolkit** 部分。

### 运行示例
<a name="id2"></a>

1. 打开 Eclipse。

1. 创建新的 AWS Java 项目。在 Eclipse 中的 **File** 菜单上，选择 **New**，然后单击 **Project**。**New Project** 向导随即打开。

1. 展开 **AWS** 类别，然后选择 **AWS Java 项目**。

1. 选择**下一步**。项目设置页面随即显示。

1. 在 **Project Name** 框中输入名称。适用于 Java 的 AWS SDK 示例组显示了 SDK 中可用的示例，如前所述。

1. 通过选中每个复选框，选择要包含在项目中的示例。

1. 输入 AWS 凭证。如果您已使用您的凭证配置 AWS Toolkit for Eclipse，则将自动填入该凭证。

1. 选择**完成**。这将创建项目并将其添加到 **Project Explorer**。

1. 选择要运行的示例 `.java` 文件。例如，对于 Amazon S3 示例，选择 `S3Sample.java`。

1. 从 **Run** 菜单中选择 **Run**。

1. 右键单击 **Project Explorer** 中的项目，指向 **Build Path**，然后选择 **Add Libraries**。

1. 选择 **AWS Java SDK**，然后选择**下一步**，并按照其余的屏幕说明执行操作。