

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# AWS Flow Framework 適用於 Java 的 入門
<a name="getting-started"></a>

本節將 AWS Flow Framework 引導您完成一系列介紹基本程式設計模型和 API 的簡單範例應用程式，以介紹 。範例應用程式是以介紹 C 和相關程式設計語言所使用的標準 Hello World 應用程式為根據。以下是 Hello World 的一般 Java 實作：

```
public class HelloWorld {
   public static void main(String[] args) {
      System.out.println("Hello World!");
   }
}
```

以下是範例應用程式的簡短說明。它們包含完整的來源碼，所以您可以自行實作並執行應用程式。開始之前，您應該先設定開發環境並建立 AWS Flow Framework 適用於 Java 的 專案，如 中的 [設定 AWS Flow Framework 適用於 Java 的](setup.md)。
+ [HelloWorld 應用程式](getting-started-example-helloworld.md) 將 Hello World 實作為標準的 Java 應用程式，但結構類似工作流程應用程式，來介紹工作流程應用程式。
+ [HelloWorldWorkflow 應用程式](getting-started-example-helloworldworkflow.md) 使用 AWS Flow Framework 適用於 Java 的 將 HelloWorld 轉換為 Amazon SWF 工作流程。
+ [HelloWorldWorkflowAsync 應用程式](getting-started-example-helloworldworkflowasync.md) 修改 `HelloWorldWorkflow` 以使用 *asynchronous workflow* 方法。
+ [HelloWorldWorkflowDistributed 應用程式](getting-started-example-helloworldworkflowdistributed.md) 修改 `HelloWorldWorkflowAsync`，以便工作流程和活動工作者可以在不同的系統中執行。
+ [HelloWorldWorkflowParallel 應用程式](getting-started-example-helloworldworkflowparallel.md) 修改 `HelloWorldWorkflow` 以平行執行兩項活動。

# 設定 AWS Flow Framework 適用於 Java 的
<a name="setup"></a>

 AWS Flow Framework 適用於 Java 的 隨附於 [適用於 Java 的 AWS SDK](https://aws.amazon.com/sdkforjava/)。如果您尚未設定 適用於 Java 的 AWS SDK，請參閱《 適用於 Java 的 AWS SDK 開發人員指南[》中的入門](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/getting-started.html)，以取得安裝和設定 SDK 本身的相關資訊。

## 使用 Maven 新增流程架構
<a name="installing-maven"></a>

Amazon SWF 建置工具是開放原始碼，若要檢視或下載程式碼或自行建置工具，請造訪位於 https：//[https://github.com/aws/aws-swf-build-tools](https://github.com/aws/aws-swf-build-tools) 的儲存庫。

Amazon 在 Maven Central Repository 中提供 [Amazon SWF 建置工具](https://mvnrepository.com/artifact/com.amazonaws/aws-swf-build-tools)。

若要設定 Maven 的流程框架，請將下列相依性新增至專案的 `pom.xml` 檔案：

```
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-swf-build-tools</artifactId>
    <version>2.0.0</version>
</dependency>
```

# HelloWorld 應用程式
<a name="getting-started-example-helloworld"></a>

為了介紹 Amazon SWF 應用程式結構的方式，我們將建立一個 Java 應用程式，其行為類似於工作流程，但在本機以單一程序執行。不需要連線到 Amazon Web Services。

**注意**  
[HelloWorldWorkflow](getting-started-example-helloworldworkflow.md) 範例以此範例為基礎，連線至 Amazon SWF 來處理工作流程的管理。

由三個基本元件組成的工作流程應用程式：
+ 「活動工作者」**支援一組「活動」**，它們每一個都是執行特定任務的獨立執行方法。
+ 「工作流程工作者」**協調活動執行並管理資料流程。其以程式設計方式具體化「工作流程拓撲」**，基本上是定義各種活動執行的時機、是依序還是同時執行等等的流程圖。
+ 「工作流程啟動者」**會啟動稱為「執行」**的工作流程執行個體，並在執行期間與之互動。

HelloWorld 實作為三種類別和兩個相關的界面，會在下列各節中說明。開始之前，您應該設定開發環境並建立新的 AWS Java 專案，如中所述[設定 AWS Flow Framework 適用於 Java 的](setup.md)。下列演練所使用的套件全都名為 `helloWorld.XYZ`。若要使用這些名稱，請在 aop.xml 中如下設定 `within` 屬性：

```
...
<weaver options="-verbose">
   <include within="helloWorld..*"/>
</weaver>
```

若要實作 HelloWorld，請在名為 的 AWS SDK 專案中建立新的 Java 套件，`helloWorld.HelloWorld`並新增下列檔案：
+ 名為 `GreeterActivities.java` 的界面檔案
+ 名為 `GreeterActivitiesImpl.java` 的類別檔案，其實作活動工作者。
+ 名為 `GreeterWorkflow.java` 的界面檔案。
+ 名為 `GreeterWorkflowImpl.java` 的類別檔案，實作工作流程工作者。
+ 名為 `GreeterMain.java` 的類別檔案，其實作工作流程啟動者。

下列各節會詳細討論，並包含各元件的完整程式碼，您可將它們新增至適當的檔案。

## HelloWorld 活動實作
<a name="getting-started-example-helloworld.activityworker"></a>

HelloWorld 會將在主控台中列印 `"Hello World!"` 歡迎語的完整任務分割成三項任務，每一個都由「活動方法」**執行。活動方法在 `GreeterActivities` 界面中定義，如下所示。

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

HelloWorld 會實作一項活動 `GreeterActivitiesImpl`，這會提供 `GreeterActivities` 方法，如下所示：

```
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);
   }
}
```

活動彼此互不影響，且通常為不同的工作流程所使用。例如，任何工作流程皆可使用 `say` 活動在主控台中列印字串。工作流程還可以實作多項活動，每一項都執行不同的任務集。

## HelloWorld 工作流程工作者
<a name="getting-started-example-helloworld.workflowworker"></a>

列印「Hello World！」 至 主控台，活動任務必須以正確的順序搭配正確的資料依序執行。HelloWorld 工作流程工作者會根據簡易的「線性工作流程拓撲」**協調活動執行，如下圖所示。

![\[線性工作流程拓撲\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/images/helloworld_topology.png)


依序執行三項活動，資料即會依照程序由一項活動流動至下一項活動。

HelloWorld 工作流程工作者只有一個方法 (工作流程的進入點)，其在 `GreeterWorkflow` 界面中定義，如下所示：

```
public interface GreeterWorkflow {
   public void greet();
}
```

`GreeterWorkflowImpl` 類別實作此界面，如下所示：

```
public class GreeterWorkflowImpl implements GreeterWorkflow{
   private GreeterActivities operations = new GreeterActivitiesImpl();

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

`greet` 方法實作 HelloWorld 拓撲的方法是：建立 `GreeterActivitiesImpl` 執行個體、依正確的順序呼叫各活動方法，然後將適當的資料傳遞到各方法。

## HelloWorld 工作流程啟動者
<a name="getting-started-example-helloworld.starter"></a>

「工作流程啟動者」**是開始執行工作流程的應用程式，也可能會與執行中的工作流程互動。`GreeterMain` 類別會實作 HelloWorld 工作流程啟動者，如下所示：

```
public class GreeterMain {
   public static void main(String[] args) {
      GreeterWorkflow greeter = new GreeterWorkflowImpl();
      greeter.greet();
   }
}
```

`GreeterMain` 會建立 `GreeterWorkflowImpl` 執行個體並呼叫 `greet` 執行工作流程工作者。`GreeterMain` 做為 Java 應用程式執行，您應該會看到「Hello World！」 在主控台輸出中。

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

雖然基本 [HelloWorld](getting-started-example-helloworld.md) 範例的結構類似於工作流程，但它與 Amazon SWF 工作流程有幾個關鍵方面不同：


**傳統和 Amazon SWF 工作流程應用程式**  

| HelloWorld | Amazon SWF 工作流程 | 
| --- | --- | 
| 以單一程序在本機執行。 | 以多個程序的形式執行，這些程序可以分散到多個系統，包括 Amazon EC2 執行個體、私有資料中心、用戶端電腦等。甚至不必執行相同的作業系統。 | 
| 活動為同步的方法，完成後才予以解鎖。 | 活動由非同步方法代表，其會立即傳回，並於等待活動完成期間，允許工作流程執行其他任務。 | 
| 工作流程工作者透過呼叫合適的方法與活動工作者互動。 | 工作流程工作者使用 HTTP 請求與活動工作者互動，Amazon SWF 充當中介裝置。 | 
| 工作流程啟動者透過呼叫合適的方法與工作流程工作者互動。 | 工作流程入門使用 HTTP 請求與工作流程工作者互動，Amazon SWF 充當中介裝置。 | 

您可以從頭開始實作分散式非同步工作流程應用程式，例如讓您的工作流程工作者透過 Web 服務呼叫，直接與活動工作者互動。但是，您必須接著實作所有必要的複雜程式碼，藉以管理多項活動的非同步執行、處理資料流程等。 AWS Flow Framework 適用於 Java 和 Amazon SWF 的 負責處理所有這些詳細資訊，這可讓您專注於實作商業邏輯。

HelloWorldWorkflow 是 HelloWorld 的修改版本，作為 Amazon SWF 工作流程執行。下圖摘要說明這兩個應用程式的運作方式。

![\[Hello World 的 Conventional 和 Amazon SWF 版本！\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/images/workflow_conceptual_welcome.png)


HelloWorld 以單一程序執行，且啟動者、工作流程工作者與活動工作者使用傳統的方法呼叫互動。透過 `HelloWorldWorkflow`，啟動者、工作流程工作者和活動工作者是使用 HTTP 請求透過 Amazon SWF 互動的分散式元件。Amazon SWF 會透過維護工作流程和活動任務的清單來管理互動，而這些任務會分派至各自的元件。本節說明 HelloWorldWorkflow 的框架運作方式。

HelloWorldWorkflow 的實作方式是使用 AWS Flow Framework 適用於 Java 的 API，可處理在背景中與 Amazon SWF 互動的有時複雜詳細資訊，並大幅簡化開發程序。您可以使用與 HelloWorld 相同的專案，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 註冊 Amazon SWF 帳戶。 [https://aws.amazon.com/swf/](https://aws.amazon.com/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 註釋 AWS Flow Framework 的兩個 [@ActivityRegistrationOptions](annotations.md#annotations-activityregistration)和 [@Activities](annotations.md#annotations-activities)套用至界面定義。註釋提供組態資訊，並指示 AWS Flow Framework for 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();
}
```

HelloWorld 也不需要此界面，但 AWS Flow Framework 對於適用於 Java 的 應用程式而言至關重要。您必須[@WorkflowRegistrationOptions](annotations.md#annotations-workflowregistrationoptions)將 Java 註釋 AWS Flow Framework 的兩個 [@工作流程](annotations.md#annotations-workflow)和 套用至工作流程界面定義。註釋提供組態資訊，並指示 AWS Flow Framework for Java 註釋處理器根據界面產生工作流程用戶端類別，如稍後所討論。

`@Workflow` 有一個選用參數 *dataConverter*，通常與其預設值 NullDataConverter 搭配使用，這表示應使用 JsonDataConverter。

`@WorkflowRegistrationOptions` 也有數個選擇性參數，可用以設定工作流程工作者。在這裡，我們將工作流程執行`defaultExecutionStartToCloseTimeoutSeconds`的時間設定為 3600 秒 (1 小時）。

`GreeterWorkflow` 界面定義和 HelloWorld 有一項重大差異：[@Execute](annotations.md#annotations-execute) 註釋。工作流程界面指定可由應用程式呼叫的方法 (例如工作流程啟動者)，並限定在少數幾個方法，各有特定的角色。框架不會指定工作流程界面方法的名稱或參數清單；您可以使用適合您工作流程的名稱和參數清單，並套用 AWS Flow Framework 適用於 Java 的 註釋來識別方法的角色。

`@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` 方法。

`GreeterActivitiesClient` 和 `GreeterActivitiesClientImpl` 類別會使用套用到您 `GreeterActivities` 類別之註釋中提供的資訊，自動為您產生。您無須自行實作。

**注意**  
Eclipse 會在您儲存專案時產生這些類別。您可在您專案目錄的 `.apt_generated` 子目錄中檢視所產生的程式碼。  
為了避免`GreeterWorkflowImpl`類別中的編譯錯誤，最佳實務是將`.apt_generated`目錄移至 **Java Build Path** 對話方塊的 **Order and Export** 索引標籤頂端。

工作流程工作者透過呼叫對應的用戶端方法執行活動。方法是非同步的，並會立即傳回 `Promise<T>` 物件，其中 `T` 是活動的傳回類型。傳回的 `Promise<T>` 物件基本上是活動方法最終傳回值的預留位置。
+ 當活動用戶端方法傳回時，`Promise<T>` 物件一開始是「未就緒狀態」**，表示物件尚未能代表有效的傳回值。
+ 當對應的活動方法完成其任務並傳回之後，框架會將傳回值指派給 `Promise<T>` 物件，讓物件進入「就緒狀態」**。

### Promise<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>` 傳回值傳遞到下一項活動，需要活動依序執行，定義前文討論過的線性拓撲。使用 AWS Flow Framework for 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>` 物件傳遞給活動用戶端方法，藉以處理此問題。您可以透過將`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. 建立 [BasicAWSCredentials](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 帳戶時建立的工作流程的 Amazon 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_tw/amazonswf/latest/awsflowguide/images/Workflow_Type.png)


如果您選擇 **Activity Types** (活動類型)，即會顯示 `GreeterActivities` 方法：

![\[HelloWorldWorkflow 活動類型\]](http://docs.aws.amazon.com/zh_tw/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 網域名稱傳遞給建構函式。用戶端 factory 物件是由框架的註釋處理器所建立，只要將 "ClientExternalFactoryImpl" 附加至工作流程界面名稱後面即可建立物件名稱。

1. 透過呼叫 factory 物件的 `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 執行工作流程，您需要回到 factory 並使用另外指定的 ID 建立新的用戶端。

工作流程用戶端公開 `GreeterMain` 呼叫以開始工作流程的 `greet` 方法，因為 `greet()` 是以 `@Execute` 註釋指定的方法。

**注意**  
註釋處理器也會建立內部用戶端 factory 物件，用以建立子工作流程。如需詳細資訊，請參閱[子工作流程執行](childworkflow.md)。

如果 `GreeterWorker` 還在執行，請暫時予以關機，然後執行 `GreeterMain`。您現在應該會在 Amazon SWF 主控台的作用中工作流程執行清單中看到 someID：。

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


如果您選擇 `someID` 和選擇 **Events** (事件) 標籤，即會顯示事件：

![\[HelloWorldWorkflow 初始工作流程事件\]](http://docs.aws.amazon.com/zh_tw/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_tw/amazonswf/latest/awsflowguide/images/Events2.png)


您可以選擇個別事件以取得詳細資訊。當您完成查看時，工作流程應該已列印「Hello World！」 至您的 主控台。

工作流程完成後，即不會出現在作用中的執行清單上。但您若想予以檢閱，請選擇 **Closed** (已結束) 執行狀態按鈕，然後選擇 **List Executions** (列出執行)。這會顯示指定網域 (`helloWorldWalkthrough`) 中所有已完成但未超過保留期的工作流程執行個體，其中保留期已於您建立網域時指定。

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


請注意，每個工作流程執行個體都有唯一的 **Run ID** (執行 ID) 值。您可以將相同的工作流程 ID 用於不同的工作流程執行個體，但一次只能用於一個作用中的執行。

# HelloWorldWorkflowAsync 應用程式
<a name="getting-started-example-helloworldworkflowasync"></a>

在某些時候會偏好讓工作流程在本機執行某些任務，而不是使用活動。不過，工作流程任務通常包含處理 `Promise<T>` 物件所代表的值。如果您將 `Promise<T>` 物件傳遞給同步工作流程方法，則會立即執行方法，但無法存取 `Promise<T>` 物件值，直到物件就緒為止。您可以輪詢 `Promise<T>.isReady`，直到傳回 `true` 為止，但此效率較顯不彰，而且方法可能會被阻擋很長一段時間。較佳的方式是使用「非同步方法」**。

非同步方法的實作方式與標準方法非常類似，通常是工作流程實作類別的成員，並且會在工作流程實作的內容中執行。套用 `@Asynchronous` 註釋 (其指示框架將之視為活動)，您即可將之指定為非同步方法。
+ 工作流程實作呼叫非同步方法時，會立即予以傳回。非同步方法一般會傳回 `Promise<T>` 物件，而此物件會在方法完成時就緒。
+ 如果您將一或多個 `Promise<T>` 物件傳遞給非同步方法，則會延遲執行，直到所有輸入物件都就緒為止。因此，非同步方法可以存取其輸入 `Promise<T>` 值，而不會發出例外狀況。

**注意**  
由於 AWS Flow Framework 適用於 Java 的 執行工作流程的方式，非同步方法通常會執行多次，因此您應該只將它們用於快速的低額外負荷任務。您應該使用活動來執行大型運算這類冗長任務。如需詳細資訊，請參閱[AWS Flow Framework 基本概念：分散式執行](awsflow-basics-distributed-execution.md)。

本主題是 HelloWorldWorkflowAsync (為 HelloWorldWorkflow 的修改版本，將其中一個活動取代為非同步方法) 的演練。若要實作應用程式，請在您的專案目錄中建立 helloWorld.HelloWorldWorkflow 套件的副本，並命名為 helloWorld.HelloWorldWorkflowAsync。

**注意**  
本主題是建置在 [HelloWorld 應用程式](getting-started-example-helloworld.md)​ 和 [HelloWorldWorkflow 應用程式](getting-started-example-helloworldworkflow.md)​ 主題所呈現的概念和檔案。熟悉這些主題呈現的檔案和概念再繼續。

下列各節說明如何修改原始 HelloWorldWorkflow 程式碼以使用非同步方法。

## HelloWorldWorkflowAsync 活動實作
<a name="getting-started-example-helloworldworkflowasync.activities"></a>

HelloWorldWorkflowAsync 會在 `GreeterActivities` 中實作其活動工作者界面，如下所示：

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

@Activities(version="2.0")
@ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 300,
                             defaultTaskStartToCloseTimeoutSeconds = 10)
public interface GreeterActivities {
   public String getName();
   public void say(String what);
}
```

此界面與 HelloWorldWorkflow 所使用的界面類似，相異之處如下：
+ 此界面會省略 `getGreeting` 活動；非同步方法現在會處理該任務。
+ 版本編號設定為 2.0。向 Amazon SWF 註冊活動界面之後，除非您變更版本號碼，否則無法修改它。

其餘的活動方法實作與 HelloWorldWorkflow 相同。只需要從 `GreeterActivitiesImpl` 中刪除 `getGreeting`。

## HelloWorldWorkflowAsync 工作流程實作
<a name="getting-started-example-helloworldworkflowasync.workflow"></a>

HelloWorldWorkflowAsync 定義工作流程界面，如下所示：

```
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 = "2.0")
   public void greet();
}
```

除了新的版本編號之外，界面會與 HelloWorldWorkflow 相同。與活動相同，如果您想要變更已註冊的工作流程，則必須變更其版本。

HelloWorldWorkflowAsync 實作工作流程，如下所示：

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

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

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

   @Asynchronous
   private Promise<String> getGreeting(Promise<String> name) {
      String returnString = "Hello " + name.get() + "!";
      return Promise.asPromise(returnString);
   }
}
```

HelloWorldWorkflowAsync 會將 `getGreeting` 活動取代為 `getGreeting` 非同步方法，但 `greet` 方法的運作方式極為相同：

1. 執行 `getName` 活動，其會立即傳回代表名稱的 `Promise<String>` 物件 `name`。

1. 呼叫 `getGreeting` 非同步方法，並將 `name` 物件遞給它。`getGreeting` 會立即傳回代表問候語的 `Promise<String>` 物件 `greeting`。

1. 執行 `say` 活動，並將 `greeting` 物件傳遞給它。

1. `getName` 完成時，`name` 會就緒，且 `getGreeting` 會使用其值來建構問候語。

1. `getGreeting` 完成時，`greeting` 會就緒，且 `say` 會將字串列印至主控台。

差異在於以問候語呼叫非同步 `getGreeting` 方法，而不是呼叫活動用戶端來執行 `getGreeting` 活動。最後的結果會相同，但 `getGreeting` 方法的運作方式與 `getGreeting` 活動有些不同。
+ 工作流程工作者會使用標準函數呼叫語意來執行 `getGreeting`。不過，活動的非同步執行是由 Amazon SWF 媒介。
+ `getGreeting` 會在工作流程實作程序中執行。
+ `getGreeting` 會傳回 `Promise<String>` 物件，而不是 `String` 物件。若要取得 `Promise` 保留的 String 值，您可以呼叫其 `get()` 方法。不過，由於活動是以非同步方式執行，其傳回值可能不會立即就緒； `get()`將引發例外狀況，直到非同步方法的傳回值可用為止。

  如需 `Promise` 運作方式的詳細資訊，請參閱「[AWS Flow Framework 基本概念：活動與工作流程之間的資料交換](awsflow-basics-data-exchange-activities-workflows.md)」。

`getGreeting` 透過將問候語字串傳遞給靜態 `Promise.asPromise` 方法，來建立傳回值。此方法會建立適當類型的 `Promise<T>` 物件，並設定值，然後讓使之進入就緒狀態。

## HelloWorldWorkflowAsync 工作流程和活動主機與啟動者
<a name="getting-started-example-helloworldworkflowasync.host"></a>

HelloWorldWorkflowAsync 將 `GreeterWorker` 實作為工作流程和活動實作的主機類別。此實作與 HelloWorldWorkflow 實作相同，差別在於 `taskListToPoll` 的名稱設為 "`HelloWorldAsyncList`"。

```
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 = "HelloWorldAsyncList";

        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();
    }
}
```

HelloWorldWorkflowAsync 會在 `GreeterMain` 中實作工作流程啟動者；與 HelloWorldWorkflow 實作相同。

若要執行工作流程，請執行 `GreeterWorker` 和 `GreeterMain`，如同 HelloWorldWorkflow。

# HelloWorldWorkflowDistributed 應用程式
<a name="getting-started-example-helloworldworkflowdistributed"></a>

使用 HelloWorldWorkflow 和 HelloWorldWorkflowAsync，Amazon SWF 會調解工作流程和活動實作之間的互動，但它們會以單一程序在本機執行。 `GreeterMain` 處於單獨的程序，但仍在相同的系統上執行。

Amazon SWF 的主要功能是支援分散式應用程式。例如，您可以在 Amazon EC2 執行個體上執行工作流程工作者、資料中心電腦上的工作流程啟動者，以及用戶端桌上型電腦上的活動。您甚至可以在不同的系統中執行不同的活動。

HelloWorldWorkflowDistributed 應用程式擴展 HelloWorldWorkflowAsync，將應用程式分散到兩個系統和三項程序。
+ 在一個系統中，工作流程和工作流程啟動者執行為不同的程序。
+ 在不同系統中執行的活動。

若要實作應用程式，請在您的專案目錄中建立 helloWorld.HelloWorldWorkflowAsync 套裝服務的複本，並命名為 helloWorld.HelloWorldWorkflowDistributed。以下各節說明如何修改原始的 HelloWorldWorkflowAsync 程式碼，將應用程式分散到兩個系統和三項程序。

您不必變更工作流程或活動實作，甚至不用變更版本編號，就可在不同的系統中執行它們。您也不必修改 `GreeterMain`。您只需要變更活動和工作流程主機。

使用 HelloWorldWorkflowAsync，單一應用程式的作用如同工作流程和活動主機。若要在不同的系統中執行工作流程和活動實作，您必須實作不同的應用程式。從專案中刪除 GreeterWorker，然後新增兩個新的類別檔案 GreeterWorkflowWorker 和 GreeterActivitiesWorker。

HelloWorldWorkflowDistributed 會在 GreeterActivitiesWorker 中實作它的活動主機，如下所示：

```
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;

public class GreeterActivitiesWorker {
   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 = "helloWorldExamples";
      String taskListToPoll = "HelloWorldAsyncList";

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

HelloWorldWorkflowDistributed 會在 `GreeterWorkflowWorker` 中實作它的工作流程主機，如下所示：

```
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.WorkflowWorker;

public class GreeterWorkflowWorker {
   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 = "helloWorldExamples";
      String taskListToPoll = "HelloWorldAsyncList";

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

請注意，`GreeterActivitiesWorker` 只是沒有 `WorkflowWorker` 程式碼的 `GreeterWorker`，而 `GreeterWorkflowWorker` 只是沒有 `ActivityWorker` 程式碼的 `GreeterWorker`。

**執行工作流程：**

1. 以 `GreeterActivitiesWorker` 做為進入點來建立可執行的 JAR 檔案。

1. 將步驟 1 的 JAR 檔案複製到另一個系統，只要支援 Java，任何作業系統皆可。

1. 確保具有相同 Amazon SWF 網域存取權的 AWS 登入資料可在其他系統上使用。

1. 執行 JAR 檔案。

1. 在您的開發系統中，使用 Eclipse 執行 `GreeterWorkflowWorker` 和 `GreeterMain`。

除了活動和工作流程工作者及工作流程啟動者在不同的系統中執行之外，工作流程運作的方式和 HelloWorldAsync 完全一致。不過，因為 `println`呼叫會列印「Hello World！」 到 主控台的活動中`say`，輸出會出現在執行活動工作者的系統上。

# HelloWorldWorkflowParallel 應用程式
<a name="getting-started-example-helloworldworkflowparallel"></a>

先前的 Hello World\$1 版本皆使用線性工作流程拓撲。不過，Amazon SWF 不限於線性拓撲。HelloWorldWorkflowParallel 應用程式即為 HelloWorldWorkflow 的修改版本，使用平行拓撲，如下圖所示。

![\[HelloWorldWorkflowParallel 工作流程拓撲\]](http://docs.aws.amazon.com/zh_tw/amazonswf/latest/awsflowguide/images/helloworld_parallel_topology.png)


使用 HelloWorldWorkflowParallel，`getName` 和 `getGreeting` 會平行執行問候語的每個傳回部分。`say` 接著會將兩個字串合併到問候語，並將之列印至主控台。

若要實作應用程式，請在您的專案目錄中建立 helloWorld.HelloWorldWorkflow 套件的副本，並命名為 helloWorld.HelloWorldWorkflowParallel。下列各節說明如何修改原始 HelloWorldWorkflow 程式碼以平行執行 `getName` 和 `getGreeting`。

## HelloWorldWorkflowParallel 活動工作者
<a name="getting-started-example-helloworldworkflowparallel.activities"></a>

HelloWorldWorkflowParallel 活動界面在 `GreeterActivities` 中實作，如下列範例所示。

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

@Activities(version="5.0")
@ActivityRegistrationOptions(defaultTaskScheduleToStartTimeoutSeconds = 300,
                             defaultTaskStartToCloseTimeoutSeconds = 10)
public interface GreeterActivities {
   public String getName();
   public String getGreeting();
   public void say(String greeting, String name);
}
```

此界面與 HelloWorldWorkflow 類似，例外狀況如下：
+ `getGreeting` 不會採用任何輸入；只會傳回問候語字串。
+ `say` 採用兩個輸入字串：問候語和名稱。
+ 界面具有新的版本編號，在您變更已註冊的界面時會需要。

HelloWorldWorkflowParallel 會實作 `GreeterActivitiesImpl` 中的活動，如下所示：

```
public class GreeterActivitiesImpl implements GreeterActivities {

   @Override
   public String getName() {
      return "World!";
   }

   @Override
   public String getGreeting() {
      return "Hello ";
   }

   @Override
   public void say(String greeting, String name) {
      System.out.println(greeting + name);
   }
}
```

`getName` 和 `getGreeting` 現在只會傳回一半的問候語字串。`say` 會串連兩個部分來產生完整片語，並將之列印至主控台。

## HelloWorldWorkflowParallel 工作流程工作者
<a name="getting-started-example-helloworldworkflowparallel-worker"></a>

HelloWorldWorkflowParallel 工作流程界面在 `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 = "5.0")
   public void greet();
}
```

類別與 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();
      operations.say(greeting, name);
   }
}
```

概述而言，此實作與 HelloWorldWorkflow 十分類似；這三個活動用戶端方法會循序執行。不過，活動不同。
+ HelloWorldWorkflow 將 `name` 傳遞給 `getGreeting`。因為 `name` 是 `Promise<T>` 物件，所以 `getGreeting` 延遲執行活動，直到 `getName` 完成，因此這兩個活動會循序執行。
+ HelloWorldWorkflowParallel 不會傳遞任何輸入 `getName` 或 `getGreeting`。任一種方法都不會延遲執行，而且會立即平行執行相關聯的活動方法。

`say` 活動會採用 `greeting` 和 `name` 做為輸入參數。因為它們是 `Promise<T>` 物件，所以 `say` 會延遲執行，直到兩個活動完成，然後建構和列印問候語。

請注意，HelloWorldWorkflowParallel 不會使用任何特殊模型程式碼來定義工作流程拓撲。它透過使用標準 Java 流程控制並利用 `Promise<T>` 物件的屬性來隱含地執行此操作。 AWS Flow Framework 對於 Java 應用程式，只需搭配傳統 Java 控制流程建構使用`Promise<T>`物件，即可實作甚至複雜的拓撲。

## HelloWorldWorkflowParallel 工作流程和活動主機與啟動者
<a name="HelloWorldWorkflowParallel-workflow-activities-host-starter"></a>

HelloWorldWorkflowParallel 將 `GreeterWorker` 實作為工作流程和活動實作的主機類別。它與 HelloWorldWorkflow 實作相同，差別在於 `taskListToPoll` 名稱設為 "HelloWorldParallelList"。

`HelloWorldWorkflowParallel` 會在 `GreeterMain` 中實作工作流程啟動者，而且與 HelloWorldWorkflow 實作相同。

若要執行工作流程，請執行 `GreeterWorker` 和 `GreeterMain`，如同 `HelloWorldWorkflow`。