

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

# HelloWorldWorkflow 应用程序
<a name="getting-started-example-helloworldworkflow"></a>

尽管基本[HelloWorld](getting-started-example-helloworld.md)示例的结构类似于工作流程，但它在几个关键方面与 Amazon SWF 工作流程有所不同：


**传统工作流应用程序和 Amazon SWF 工作流应用程序**  

| HelloWorld | Amazon SWF Workflow | 
| --- | --- | 
| 在本地作为单个进程运行。 | 作为多个进程运行，可以分布在多个系统中，包括 Amazon EC2 实例、私有数据中心、客户端计算机等。这些进程甚至不必运行在相同的操作系统上。 | 
| 活动是同步方法，在完成前保持阻止状态。 | 活动表示为异步方法，立即返回，并允许工作流程在等待活动完成时执行其他任务。 | 
| 工作流程工作线程通过调用适当的方法与活动工作线程交互。 | 工作流工作线程使用 HTTP 请求与活动工作线程交互，而 Amazon SWF 则充当中介。 | 
| 工作流程启动程序通过调用相应的方法与工作流程工作线程交互。 | 工作流启动程序使用 HTTP 请求与工作流工作线程交互，而 Amazon SWF 则充当中介。 | 

您可以从头开始实施分布式异步工作流程应用程序，例如，让您的工作流程工作线程直接通过 Web 服务调用与活动工作线程交互。不过，随后您必须实施管理异步执行多个活动、处理数据流等所需的所有复杂代码。f AWS Flow Framework or Java 和 Amazon SWF 负责所有这些细节，这使您可以专注于实现业务逻辑。

HelloWorldWorkflow 是作为 Amazon SWF 工作流程运行的修改版。 HelloWorld 下图总结了两个应用程序的工作原理。

![\[传统版 Hello World! 和 Amazon SWF 版 Hello World!\]](http://docs.aws.amazon.com/zh_cn/amazonswf/latest/awsflowguide/images/workflow_conceptual_welcome.png)


HelloWorld 作为单个进程运行，启动者、工作流程工作人员和活动工作者使用传统的方法调用进行交互。对于 HelloWorldWorkflow，启动程序、工作流工作线程和活动工作线程是分布式组件，通过 Amazon SWF 使用 HTTP 请求进行交互。Amazon SWF 通过维护工作流和活动任务列表来管理交互，并将这些工作流和任务分派给相应的组件。本节介绍该框架的工作原理 HelloWorldWorkflow。

HelloWorldWorkflow 是通过使用 for Java API 实现的，该API可以处理有时在后台与 Amazon SWF 交互的复杂细节，并大大简化了开发过程。 AWS Flow Framework 您可以使用与您为之相同的项目 HelloWorld，该项目已针对 Java 应用程序进行了配置。 AWS Flow Framework 但是，要运行该应用程序，您必须按如下所示设置 Amazon SWF 账户：
+ 如果您还没有 AWS 账户，请在 [Amazon Web Services](https://aws.amazon.com/) 上注册一个账户。
+ 将您账户的访问权限 ID 和私密 ID 分别分配给 AWS\$1ACCESS\$1KEY\$1ID 和 AWS\$1SECRET\$1KEY 环境变量。最好不要在代码中暴露文本密钥值。将它们存储在环境变量中是一种方便处理问题的方法。
+ 在 [Amazon Simple Workflow Service](https://aws.amazon.com/swf/) 注册 Amazon SWF 账户。
+ 登录 AWS 管理控制台 并选择 Amazon SWF 服务。
+ 选择右上角的**管理域**，然后注册一个新的 Amazon SWF 域。*域* 是一个应用程序资源 (例如工作流程和活动类型) 和工作流程执行的逻辑容器。您可以使用任何方便的域名，但演练使用 “helloWorldWalkthrough”。

要实现 HelloWorldWorkflow，请创建 HelloWorld 的副本。 HelloWorld 打包到你的项目目录中然后把它命名为 HelloWorld。 HelloWorldWorkflow。以下各节介绍如何修改原始 HelloWorld代码以使用 AWS Flow Framework 适用于 Java 并作为 Amazon SWF 工作流程应用程序运行。

## HelloWorldWorkflow 活动工作者
<a name="getting-started-example-helloworldworkflow.activities"></a>

HelloWorld 将其活动工人作为一个班级实施。 AWS Flow Framework 适用于 Java 的活动工作程序有三个基本组件：
+ *活动方法*：用于执行实际任务，在接口中定义，并在相关类中实现。
+ [ActivityWorker](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/ActivityWorker.html)类管理活动方法与 Amazon SWF 之间的交互。
+ *活动宿主* 应用程序注册并启动活动工作线程，以及处理清除操作。

此部分讨论活动方法；另外两个类在后文中讨论。

HelloWorldWorkflow 定义了中的活动接口`GreeterActivities`，如下所示：

```
import com.amazonaws.services.simpleworkflow.flow.annotations.Activities;
import com.amazonaws.services.simpleworkflow.flow.annotations.ActivityRegistrationOptions;

@ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 300,
                             defaultTaskStartToCloseTimeoutSeconds = 10)
@Activities(version="1.0")

public interface GreeterActivities {
   public String getName();
   public String getGreeting(String name);
   public void say(String what);
}
```

这个接口并不是绝对必要的 HelloWorld，但它是用于 Java AWS Flow Framework 的应用程序的。请注意，接口定义本身并未更改。但是，必须将 Java 标注[@ActivityRegistrationOptions](annotations.md#annotations-activityregistration)和[@活动](annotations.md#annotations-activities)应用于接口定义。 AWS Flow Framework 这些注解提供配置信息，并指 AWS Flow Framework 示 Java 注解处理器使用接口定义生成*活动客户端*类，稍后将对此进行讨论。

`@ActivityRegistrationOptions`有多个命名值，用于配置活动的行为。 HelloWorldWorkflow 指定了两个超时：
+ `defaultTaskScheduleToStartTimeoutSeconds` 指定任务可以在活动任务列表中排队的时间长度，设置为 300 秒 (5 分钟)。
+ `defaultTaskStartToCloseTimeoutSeconds` 指定活动执行任务可以使用的最长时间，设置为 10 秒。

这些超时确保活动在合理的时间范围内完成其任务。如果超过了任何超时，该框架会生成错误，工作流程工作线程必须决定如何处理问题。有关如何处理此类错误的讨论，请参阅[错误处理](errorhandling.md)。

`@Activities` 有多个值，不过通常仅指定活动的版本号，您可以通过该版本号来跟踪活动实施的不同代。如果您在将活动接口注册到 Amazon SWF 之后对其进行了更改，包括更改 `@ActivityRegistrationOptions` 值，那么您必须使用新版本号。

HelloWorldWorkflow 在中实现活动方法`GreeterActivitiesImpl`，如下所示：

```
public class GreeterActivitiesImpl implements GreeterActivities {
   @Override
   public String getName() {
      return "World";
   }
   @Override
   public String getGreeting(String name) {
      return "Hello " + name;
   }
   @Override
   public void say(String what) {
      System.out.println(what);
   }
}
```

请注意，该代码与 HelloWorld 实现相同。从本质上讲， AWS Flow Framework 活动只是一种执行某些代码并可能返回结果的方法。标准应用程序与 Amazon SWF 工作流应用程序的区别在于工作流如何执行活动、在哪里执行活动以及如何将结果返回到工作流工作线程。

## HelloWorldWorkflow 工作流程工作者
<a name="getting-started-example-helloworldworkflow.workflow"></a>

Amazon SWF 工作流工作线程包含三个基本组件。
+ *工作流程实施*，这是执行与工作流程相关任务的类。
+ *活动客户端* 类，这基本上活动类的代理，由工作流程实施用于异步执行活动方法。
+ 一个[WorkflowWorker](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/WorkflowWorker.html)类，用于管理工作流程与 Amazon SWF 之间的交互。

此部分讨论工作流程实施和活动客户端；`WorkflowWorker` 类将在后文讨论。

HelloWorldWorkflow 在中定义了工作流界面`GreeterWorkflow`，如下所示：

```
import com.amazonaws.services.simpleworkflow.flow.annotations.Execute;
import com.amazonaws.services.simpleworkflow.flow.annotations.Workflow;
import com.amazonaws.services.simpleworkflow.flow.annotations.WorkflowRegistrationOptions;

@Workflow
@WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 3600)
public interface GreeterWorkflow {
   @Execute(version = "1.0")
   public void greet();
}
```

对于适用于 Java 的应用程序来说，这个接口也不是必需的， HelloWorld AWS Flow Framework 但却是必不可少的。必须将 Java AWS Flow Framework 标注[@工作流](annotations.md#annotations-workflow)和[@WorkflowRegistrationOptions](annotations.md#annotations-workflowregistrationoptions)应用于工作流界面定义。这些注解提供了配置信息，还指示 AWS Flow Framework Java 注解处理器根据接口生成工作流客户端类，如后面所述。

`@Workflow`有一个可选参数 *DataConvert* er，该参数通常与其默认值一起使用 NullDataConverter，表示应使用默认值。 JsonDataConverter 

`@WorkflowRegistrationOptions` 还有多个可选的参数，这些参数可用于配置工作流程工作线程。在这里，我们将 `defaultExecutionStartToCloseTimeoutSeconds`（指定工作流的运行时间）设置为 3600 秒（1 小时）。

`GreeterWorkflow`接口定义与[@Execute](annotations.md#annotations-execute)注释 HelloWorld 的不同之处在于一个重要方面。工作流程接口指定可由应用程序调用的方法，例如工作流程启动程序，并且限制为几个方法，每种方法具有特定角色。该框架不指定工作流接口方法的名称或参数列表；您可以使用适合您工作流的名称和参数列表，并应用适用于 Java 的 AWS Flow Framework 注释来标识方法的角色。

`@Execute` 有两个用途：
+ 它确定 `greet` 作为工作流程的入口点，也就是工作流程启动程序调用以启动工作流程的方法。通常，入口点可以接受一个或多个参数，这使得启动程序可以初始化工作流程，但本示例中无需初始化。
+ 它指定工作流程的版本号，通过该版本号可以跟踪工作流程实施的不同代。要在将工作流接口注册到 Amazon SWF 之后对其进行更改（包括更改超时值），您必须使用新版本号。

有关可包括在工作流程接口中的其他方法的信息，请参阅[工作流和活动合同](features.workflow.md)。

HelloWorldWorkflow 在中实现工作流程`GreeterWorkflowImpl`，如下所示：

```
import com.amazonaws.services.simpleworkflow.flow.core.Promise;

public class GreeterWorkflowImpl implements GreeterWorkflow {
   private GreeterActivitiesClient operations = new GreeterActivitiesClientImpl();

   public void greet() {
     Promise<String> name = operations.getName();
     Promise<String> greeting = operations.getGreeting(name);
     operations.say(greeting);
   }
}
```

该代码与类似 HelloWorld，但有两个重要区别。
+ `GreeterWorkflowImpl` 创建活动客户端 `GreeterActivitiesClientImpl` 的实例，而不是 `GreeterActivitiesImpl`，并通过在客户端对象上调用方法来执行活动。
+ 命名和问候活动返回 `Promise<String>` 对象而不是 `String` 对象。

HelloWorld 是一个作为单个进程在本地运行的标准 Java 应用程序，因此`GreeterWorkflowImpl`只需创建的实例`GreeterActivitiesImpl`、按顺序调用方法并将返回值从一个活动传递到下一个活动即可实现工作流拓扑。使用 Amazon SWF 工作流，活动的任务仍由来自 `GreeterActivitiesImpl` 的活动方法执行。但是，该方法不一定要在与工作流程相同的进程中运行，甚至可以运行在不同系统上，工作流程需要异步执行活动。这些要求引发了下列问题：
+ 如何执行可能运行在不同进程中 (也有可能运行在不同系统上) 的活动方法。
+ 如何异步执行活动方法。
+ 如何管理活动的输入和返回值。例如，如果活动 A 返回的值是活动 B 的输入，您必须确保活动 B 不会在活动 A 完成之前执行。

您可以使用熟悉的 Java 流程控制并与活动客户端和 `Promise<T>` 相结合，通过应用程序的控制流程实施各种工作流程拓扑。

### 活动客户端
<a name="getting-started-example-helloworldworkflow.workflow.client"></a>

`GreeterActivitiesClientImpl` 基本上是 `GreeterActivitiesImpl` 的代理，允许工作流程实施异步执行 `GreeterActivitiesImpl` 方法。

使用应用到您的 `GreeterActivities` 类的注释中提供的信息，自动为您生成 `GreeterActivitiesClient` 和 `GreeterActivitiesClientImpl` 类。您无需自行实施这些内容。

**注意**  
Eclipse 会在您保存项目时生成这些类。您可在项目目录的 `.apt_generated` 子目录中查看生成的代码。  
为避免 `GreeterWorkflowImpl` 类中出现编译错误，最好将 `.apt_generated` 目录移至 **Java 生成路径**对话框的**排序和导出**选项卡顶部。

工作流程工作线程通过调用对应的客户端方法来执行活动。该方法异步执行，并立即返回 `Promise<T>` 对象，其中 `T` 是活动的返回类型。返回的 `Promise<T>` 对象基本上是活动方法最终将返回的值的占位符。
+ 当活动客户端方法返回时，`Promise<T>` 对象最初处于*未就绪状态*，这表示对象尚未提供有效返回值。
+ 当对应的活动方法完成其任务并返回时，该框架会将返回值分配给 `Promise<T>` 对象并将其置于*就绪状态*。

### 承诺 <T> 类型
<a name="getting-started-example-helloworldworkflow.workflow.promise"></a>

`Promise<T>` 对象的主要用途是管理异步组件之间的数据流并控制什么时候执行。它使得应用程序无需明确管理同步或依赖于计时器等机制来确保异步组件不会过早执行。当您调用活动客户端方法时，它会立即返回，但框架会延迟对应活动方法的执行，直至输入 `Promise<T>` 对象已就绪并提供了有效值。

从 `GreeterWorkflowImpl` 的角度，全部三个活动客户端方法立即返回。从 `GreeterActivitiesImpl` 的角度，框架在 `name` 完成前不会调用 `getGreeting`，并且在 `getGreeting` 完成前不会调用 `say`。

通过使用 `Promise<T>` 将数据从一个活动传递到另一个，`HelloWorldWorkflow` 不仅确保活动方法不会尝试使用无效数据，还会控制执行活动的时间并隐式定义工作流程拓扑。将每个活动的 `Promise<T>` 返回值传递到下一个活动时，需要按顺序执行活动，后文中将讨论定义线性拓扑。使用 f AWS Flow Framework or Java，您无需使用任何特殊的建模代码来定义甚至复杂的拓扑，只需使用标准的 Java 流量控制和`Promise<T>`。有关如何实施简单并行拓扑的示例，请参阅[HelloWorldWorkflowParallel 活动工作者](getting-started-example-helloworldworkflowparallel.md#getting-started-example-helloworldworkflowparallel.activities)。

**注意**  
当 `say` 等活动方法未返回值时，对应的客户端方法会返回 `Promise<Void>` 对象。对象不提供数据，不过最初它处于未就绪状态，并在活动完成后处于就绪状态。因此，您可以将 `Promise<Void>` 对象传递到其他活动客户端方法，确保它们延迟执行直至原始活动完成。

`Promise<T>` 允许工作流程实施使用活动客户端方法及其返回值，这类似于同步方法。但是，对于访问 `Promise<T>` 对象的值，您务必保持谨慎。与 Java [Future<T>](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html) 类型不同，该框架处理 `Promise<T>` 而非应用程序的同步。如果您调用 `Promise<T>.get`，但对象未准备就绪，则 `get` 会引发异常。请注意，`HelloWorldWorkflow` 从不直接访问 `Promise<T>` 对象；它仅将对象从一个活动传递到下一个。在对象就绪之后，框架提取值并将其作为标准类型传递到活动方法。

`Promise<T>` 对象仅应由异步代码访问，其中框架确保对象已就绪并提供了有效值。`HelloWorldWorkflow` 通过仅将 `Promise<T>` 对象传递到活动客户端方法来处理此问题。您可以在工作流实现中访问 对象的值，方法是将该对象传递给异步工作流方法，该方法的行为与活动非常相似。有关示例，请参阅[HelloWorldWorkflowAsync 应用程序](getting-started-example-helloworldworkflowasync.md)。

## HelloWorldWorkflow 工作流程和活动实施
<a name="getting-started-example-helloworldworkflow.host"></a>

工作流程和活动实现具有关联的工作人员类[ActivityWorker](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/ActivityWorker.html)和[WorkflowWorker](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/WorkflowWorker.html)。它们通过轮询相应 Amazon SWF 任务列表中以获取任务、为每个任务执行相应的方法以及管理数据流，来处理 Amazon SWF 与活动和工作流实现之间的通信。有关详细信息，请参阅 [AWS Flow Framework 基本概念：应用程序结构](awsflow-basics-application-structure.md)

要将活动和工作流程实施与对应的工作线程对象关联，您需要实施一个或多个工作线程应用程序，以便：
+ 将工作流或活动注册到 Amazon SWF。
+ 创建工作线程对象并将这些对象与工作流程或活动工作线程实施关联。
+ 指示工作线程对象开始与 Amazon SWF 通信。

如果您希望将工作流程和活动作为单独的进程运行，则必须实施单独的工作流程和活动工作线程宿主。有关示例，请参阅[HelloWorldWorkflowDistributed 应用程序](getting-started-example-helloworldworkflowdistributed.md)。为简单起见， HelloWorldWorkflow实现了在同一进程中运行活动和工作流工作人员的单个工作主机，如下所示：

```
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient;
import com.amazonaws.services.simpleworkflow.flow.ActivityWorker;
import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker;

public class GreeterWorker  {
   public static void main(String[] args) throws Exception {
     ClientConfiguration config = new ClientConfiguration().withSocketTimeout(70*1000);

     String swfAccessId = System.getenv("AWS_ACCESS_KEY_ID");
     String swfSecretKey = System.getenv("AWS_SECRET_KEY");
     AWSCredentials awsCredentials = new BasicAWSCredentials(swfAccessId, swfSecretKey);

     AmazonSimpleWorkflow service = new AmazonSimpleWorkflowClient(awsCredentials, config);
     service.setEndpoint("https://swf.us-east-1.amazonaws.com");

     String domain = "helloWorldWalkthrough";
     String taskListToPoll = "HelloWorldList";

     ActivityWorker aw = new ActivityWorker(service, domain, taskListToPoll);
     aw.addActivitiesImplementation(new GreeterActivitiesImpl());
     aw.start();

     WorkflowWorker wfw = new WorkflowWorker(service, domain, taskListToPoll);
     wfw.addWorkflowImplementationType(GreeterWorkflowImpl.class);
     wfw.start();
   }
}
```

`GreeterWorker`没有 HelloWorld 对应的类，因此必须`GreeterWorker`向项目中添加一个名为的 Java 类，然后将示例代码复制到该文件中。

第一步是创建和配置一个[AmazonSimpleWorkflowClient](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/AmazonSimpleWorkflowClient.html)对象，该对象调用底层 Amazon SWF 服务方法。为此，`GreeterWorker` 将会：

1. 创建一个[ClientConfiguration](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/ClientConfiguration.html)对象并将套接字超时指定为 70 秒。此值指定在已建立的开放连接上等待数据传输的时间长度，超过该时间将关闭套接字。

1. 创建一个 B [asic AWSCredentials](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/BasicAWSCredentials.html) 对象来标识 AWS 账户，并将账户密钥传递给构造函数。为方便起见以及避免在代码中以纯文本格式暴露密钥，密钥作为环境变量存储。

1. 创建一个[AmazonSimpleWorkflowClient](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/AmazonSimpleWorkflowClient.html)对象来表示工作流程，并将`BasicAWSCredentials`和`ClientConfiguration`对象传递给构造函数。

1. 设置客户端对象的服务端点 URL。Amazon SWF 目前已在所有 AWS 地区上市。

为方便起见，`GreeterWorker` 定义两个字符串常量。
+ `domain`是工作流程的 Amazon SWF 域名，它是您在设置亚马逊 SWF 账户时创建的。 `HelloWorldWorkflow`假设您正在 “helloWorldWalkthrough” 域中运行工作流程。
+ `taskListToPoll` 是 Amazon SWF 用来管理工作流与活动工作线程之间的通信的任务列表的名称。您可以将名称设置为任何方便的字符串。 HelloWorldWorkflow 在工作流和活动任务列表中都使用 HelloWorldList “”。在后台，这些名称对应着不同的命名空间，因此两个任务列表是不同的。

`GreeterWorker`使用字符串常量和对象创建工作线程[AmazonSimpleWorkflowClient](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/AmazonSimpleWorkflowClient.html)对象，这些对象管理活动和工作程序实现与 Amazon SWF 之间的交互。具体而言，工作线程对象处理轮询相应任务列表以查找任务的工作。

`GreeterWorker` 创建 `ActivityWorker` 对象，并通过添加新的类实例将其配置为处理 `GreeterActivitiesImpl`。`GreeterWorker` 然后调用 `ActivityWorker` 对象的 `start` 方法，该方法会指导对象开始轮询指定的活动任务列表。

`GreeterWorker` 创建 `WorkflowWorker` 对象，并通过添加类文件名 `GreeterWorkflowImpl.class` 将其配置为处理 `GreeterWorkflowImpl`。然后，它会调用 `WorkflowWorker` 对象的 `start` 方法，这会指导对象开始轮询指定的工作流程任务列表。

此时您可以成功运行 `GreeterWorker`。它将工作流和活动注册到 Amazon SWF，并启动工作线程对象来轮询其相应的任务列表。要验证这一点，请运行 `GreeterWorker` 并转到 Amazon SWF 控制台，然后从域列表中选择 `helloWorldWalkthrough`。如果在**导航**窗格中选择**工作流类型**，您应该会看到 `GreeterWorkflow.greet`：

![\[HelloWorldWorkflow 工作流程类型\]](http://docs.aws.amazon.com/zh_cn/amazonswf/latest/awsflowguide/images/Workflow_Type.png)


如果选择 **Activity Types** (活动类型)，则将显示 `GreeterActivities` 方法：

![\[HelloWorldWorkflow 活动类型\]](http://docs.aws.amazon.com/zh_cn/amazonswf/latest/awsflowguide/images/Activity_Types.png)


不过，如果您选择 **Workflow Executions** (工作流程执行)，则不会看到任何处于活动状态的执行。虽然工作流程和活动工作线程正在轮询任务，但我们尚未启动工作流程执行。

## HelloWorldWorkflow 入门
<a name="getting-started-example-helloworldworkflow.starter"></a>

最后一道难题是实施工作流程启动程序，这是启动工作流程执行的应用程序。执行状态由 Amazon SWF 存储，因此您可以查看其历史和执行状态。 HelloWorldWorkflow 通过修改`GreeterMain`类来实现工作流程启动器，如下所示：

```
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflow;
import com.amazonaws.services.simpleworkflow.AmazonSimpleWorkflowClient;

public class GreeterMain {

   public static void main(String[] args) throws Exception {
     ClientConfiguration config = new ClientConfiguration().withSocketTimeout(70*1000);

     String swfAccessId = System.getenv("AWS_ACCESS_KEY_ID");
     String swfSecretKey = System.getenv("AWS_SECRET_KEY");
     AWSCredentials awsCredentials = new BasicAWSCredentials(swfAccessId, swfSecretKey);

     AmazonSimpleWorkflow service = new AmazonSimpleWorkflowClient(awsCredentials, config);
     service.setEndpoint("https://swf.us-east-1.amazonaws.com");

     String domain = "helloWorldWalkthrough";

     GreeterWorkflowClientExternalFactory factory = new GreeterWorkflowClientExternalFactoryImpl(service, domain);
     GreeterWorkflowClientExternal greeter = factory.getClient("someID");
     greeter.greet();
   }
}
```

`GreeterMain` 使用与 `GreeterWorker` 相同的代码创建 `AmazonSimpleWorkflowClient` 对象。然后创建 `GreeterWorkflowClientExternal` 对象，该对象用作工作流程的代理，其方式与在 `GreeterWorkflowClientImpl` 中创建的活动客户端用作活动方法的代理大致相同。您无需使用 `new` 创建工作流程客户端对象，而是需要：

1. 创建外部客户端工厂对象，并将 `AmazonSimpleWorkflowClient` 对象和 Amazon SWF 域名传递到构造函数。客户端工厂对象由框架的注释处理器创建，它只需在工作流程接口名称后附加 “ClientExternalFactoryImpl” 即可创建对象名称。

1. 通过调用工厂对象的`getClient`方法来创建外部客户端对象，该方法通过在工作流程接口名称后附加 ClientExternal “” 来创建对象名称。您可以选择向 `getClient` 传递一个字符串，Amazon SWF 将使用该字符串来标识此工作流实例。否则，Amazon SWF 将使用生成的 GUID 来表示工作流实例。

从工厂返回的客户端将仅创建以传入 [getClient](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/simpleworkflow/flow/WorkflowClientFactoryExternal.html#getClient(java.lang.String)) 方法的字符串命名的工作流（从工厂返回的客户端在 Amazon SWF 中已拥有状态）。要运行具有不同 ID 的工作流程，您需要返回到工厂并使用指定的不同 ID 创建新客户端。

工作流程客户端公开 `greet` 方法，`GreeterMain` 调用该方法来启动工作流程，因为 `greet()` 是使用 `@Execute` 注释指定的方法。

**注意**  
注释处理器还会创建用于创建子工作流程的内部客户端工厂对象。有关更多信息，请参阅 [子工作流程执行](childworkflow.md)。

如果当前 `GreeterWorker` 仍在运行，则关闭它，并运行 `GreeterMain`。现在，您应该可以在 Amazon SWF 控制台的活动工作流执行列表中看到 someID：

![\[HelloWorldWorkflow 工作流程执行\]](http://docs.aws.amazon.com/zh_cn/amazonswf/latest/awsflowguide/images/Active_Execution.png)


如果您选择 `someID` 并选择 **Events** (事件) 选项卡，则将显示事件：

![\[HelloWorldWorkflow 初始工作流程事件\]](http://docs.aws.amazon.com/zh_cn/amazonswf/latest/awsflowguide/images/Events1.png)


**注意**  
如果您之前启动了 `GreeterWorker` 并且它仍在运行，则会看到较长的事件列表，其原因刚刚讨论过。停止 `GreeterWorker` 并尝试重新运行 `GreaterMain`。

**Events** (事件) 选项卡仅显示两个事件：
+ `WorkflowExecutionStarted` 指示工作流程已开始执行。
+ `DecisionTaskScheduled` 表示 Amazon SWF 已将第一个决策任务排队。

在执行第一个决策任务时阻止工作流程的原因是，工作流程分布在两个应用程序（`GreeterMain` 和 `GreeterWorker`）上。`GreeterMain` 启动了工作流程执行，但 `GreeterWorker` 未运行，因此工作线程不会轮询列表和执行任务。您可以独立运行任何一个应用程序，不过工作流程执行需要两个应用程序，才能在第一个决策任务之后继续。如果您现在运行 `GreeterWorker`，则工作流程和活动工作线程将开始轮询，各个任务会快速完成。如果您现在查看 `Events` (事件) 选项卡，将显示第一批事件。

![\[HelloWorldWorkflow 完成工作流程事件\]](http://docs.aws.amazon.com/zh_cn/amazonswf/latest/awsflowguide/images/Events2.png)


您可以选择单独的事件来获取更多信息。在您查看完之后，工作流应该已将“Hello World\$1” 输出到您的控制台。

当工作流程完成后，不再显示在活动执行的列表上。不过，如果您希望查看它，请选择 **Closed** (已关闭) 执行状态，然后选择 **List Executions** (列出执行)。这将显示指定域 (`helloWorldWalkthrough`) 中未超过其保留时间的所有已完成工作流程实例，该保留时间是在您创建域时指定的。

![\[HelloWorldWorkflow 已完成的工作流程\]](http://docs.aws.amazon.com/zh_cn/amazonswf/latest/awsflowguide/images/Closed_Workflows.png)


请注意，每个工作流程实例具有一个唯一的 **Run ID** (运行 ID) 值。您可以将相同的工作流程 ID 用于不同的工作流程实例，但一次只能用于一个活动执行。