

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

# 使用 Amazon SQS Java Messaging Library
<a name="getting-started"></a>

若要開始使用 Java 訊息服務 (JMS) 搭配 Amazon SQS，請使用本節中的程式碼範例。以下章節會示範如何建立 JMS 連線和工作階段，以及如何傳送和接收訊息。

包含在 Amazon SQS Java 訊息程式庫的包裝 Amazon SQS 用戶端物件會檢查 Amazon SQS 佇列是否存在。如果佇列不存在，用戶端便會建立佇列。

## 建立 JMS 連線
<a name="creating-connection"></a>

開始之前，請參閱 中的先決條件[使用 JMS 和 Amazon SQS 的先決條件](prerequisites.md)。

1. 請建立連現工廠並對工廠呼叫 `createConnection` 方法。

   ```
   // Create a new connection factory with all defaults (credentials and region) set automatically
   SQSConnectionFactory connectionFactory = new SQSConnectionFactory(
           new ProviderConfiguration(),
           AmazonSQSClientBuilder.defaultClient()
           );
    
   // Create the connection.
   SQSConnection connection = connectionFactory.createConnection();
   ```

   `SQSConnection` 類別會將 `javax.jms.Connection` 延伸。搭配 JMS 標準連線方法，`SQSConnection` 會提供額外的方法，例如 `getAmazonSQSClient` 和 `getWrappedAmazonSQSClient`。兩種方法皆能執行不包含在 JMS 規格內的管理操作，例如建立新佇列。不過，`getWrappedAmazonSQSClient` 方法還可提供目前連線使用的 Amazon SQS 用戶端的包裝版本。包裝函式會將每個例外狀況從用戶端的轉換為 `JMSException`，讓如此可更輕鬆地由預期 `JMSException` 事件的既有程式碼使用。

1. 您可以使用 `getAmazonSQSClient` 及 `getWrappedAmazonSQSClient` 傳回的用戶端物件來執行未包含在 JMS 規格內的管理操作 (例如建立 Amazon SQS 佇列)。

    若有會預期 JMS 例外狀況出現的既有程式碼，則應使用 `getWrappedAmazonSQSClient`：
   + 若您使用 `getWrappedAmazonSQSClient`，傳回的用戶端物件會將所有例外狀況轉換為 JMS 例外狀況。
   + 若您使用 `getAmazonSQSClient`，例外狀況全為 Amazon SQS 例外狀況。

## 建立 Amazon SQS 佇列
<a name="creating-queue"></a>

包裝用戶端物件會檢查 Amazon SQS 佇列是否存在。

如果佇列不存在，用戶端便會建立佇列。如果佇列存在，該函數不會傳回任何內容。如需詳細資訊，請參閱視需要建立佇列章節的 [TextMessageSender.java](sqs-jms-code-examples.md#example-sender) 範例。

### 建立標準佇列
<a name="creating-queue-standard"></a>

```
// Get the wrapped client
AmazonSQSMessagingClientWrapper client = connection.getWrappedAmazonSQSClient();
 
// Create an SQS queue named MyQueue, if it doesn't already exist
if (!client.queueExists("MyQueue")) {
    client.createQueue("MyQueue");
}
```

### 若要建立 FIFO 佇列
<a name="creating-queue-FIFO"></a>

```
// Get the wrapped client
AmazonSQSMessagingClientWrapper client = connection.getWrappedAmazonSQSClient();

// Create an Amazon SQS FIFO queue named MyQueue.fifo, if it doesn't already exist
if (!client.queueExists("MyQueue.fifo")) {
    Map<String, String> attributes = new HashMap<String, String>();
    attributes.put("FifoQueue", "true");
    attributes.put("ContentBasedDeduplication", "true");
    client.createQueue(new CreateQueueRequest().withQueueName("MyQueue.fifo").withAttributes(attributes));
}
```

**注意**  
FIFO 佇列名稱結尾必須是 `.fifo` 尾碼。  
如需 `ContentBasedDeduplication` 屬性的相關資訊，請參閱[Amazon SQS 中的精確一次處理](FIFO-queues-exactly-once-processing.md)。

## 同步傳送訊息
<a name="send-messages-synchronously"></a>

1. 當連線和底層的 Amazon SQS 佇列準備好之時，請以 `AUTO_ACKNOWLEDGE` 模式建立非交易的 JMS 工作階段。

   ```
   // Create the nontransacted session with AUTO_ACKNOWLEDGE mode
   Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
   ```

1. 若要傳送文字訊息到佇列，請建立 JMS 佇列身分和訊息生產者。

   ```
   // Create a queue identity and specify the queue name to the session
   Queue queue = session.createQueue("MyQueue");
    
   // Create a producer for the 'MyQueue'
   MessageProducer producer = session.createProducer(queue);
   ```

1. 請建立文字訊息，並傳送到佇列。
   + 若要傳送訊息到標準佇列，則無需設定任何額外參數。

     ```
     // Create the text message
     TextMessage message = session.createTextMessage("Hello World!");
      
     // Send the message
     producer.send(message);
     System.out.println("JMS Message " + message.getJMSMessageID());
     ```
   + 若要傳送訊息到 FIFO 佇列，則必須設定訊息群組 ID。您也可以設定訊息重複資料刪除 ID。如需詳細資訊，請參閱 [Amazon SQS FIFO 佇列金鑰術語](FIFO-key-terms.md)。

     ```
     // Create the text message
     TextMessage message = session.createTextMessage("Hello World!");
     
     // Set the message group ID
     message.setStringProperty("JMSXGroupID", "Default");
     
     // You can also set a custom message deduplication ID
     // message.setStringProperty("JMS_SQS_DeduplicationId", "hello");
     // Here, it's not needed because content-based deduplication is enabled for the queue
     
     // Send the message
     producer.send(message);
     System.out.println("JMS Message " + message.getJMSMessageID());
     System.out.println("JMS Message Sequence Number " + message.getStringProperty("JMS_SQS_SequenceNumber"));
     ```

## 同步接收訊息
<a name="receive-messages-synchronously"></a>

1. 若要接收訊息，請建立相同佇列的消費者並呼叫 `start` 方法。

   您可以隨時在連線上呼叫 `start` 方法。不過，消費者在您呼叫前不會接收訊息。

   ```
   // Create a consumer for the 'MyQueue'
   MessageConsumer consumer = session.createConsumer(queue);
   // Start receiving incoming messages
   connection.start();
   ```

1. 請在消費者上呼叫 `receive` 方法呼叫，將逾時設定為 1 秒，然後將接收訊息的內容列印出來。
   + 從標準佇列接收訊息後，即可存取訊息內容。

     ```
     // Receive a message from 'MyQueue' and wait up to 1 second
     Message receivedMessage = consumer.receive(1000);
      
     // Cast the received message as TextMessage and display the text
     if (receivedMessage != null) {
         System.out.println("Received: " + ((TextMessage) receivedMessage).getText());
     }
     ```
   + 從 FIFO 佇列接收訊息後，即可存取訊息的內容和其他 FIFO 特定的訊息屬性，例如訊息群組 ID、訊息重複資料刪除 ID 和序號。如需詳細資訊，請參閱 [Amazon SQS FIFO 佇列金鑰術語](FIFO-key-terms.md)。

     ```
     // Receive a message from 'MyQueue' and wait up to 1 second
     Message receivedMessage = consumer.receive(1000);
     
     // Cast the received message as TextMessage and display the text
     if (receivedMessage != null) {
         System.out.println("Received: " + ((TextMessage) receivedMessage).getText());
         System.out.println("Group id: " + receivedMessage.getStringProperty("JMSXGroupID"));
         System.out.println("Message deduplication id: " + receivedMessage.getStringProperty("JMS_SQS_DeduplicationId"));
         System.out.println("Message sequence number: " + receivedMessage.getStringProperty("JMS_SQS_SequenceNumber"));
     }
     ```

1. 關閉連線和工作階段。

   ```
   // Close the connection (and the session).
   connection.close();
   ```

輸出結果類似如下：

```
JMS Message ID:8example-588b-44e5-bbcf-d816example2
Received: Hello World!
```

**注意**  
您可以使用 Spring Framework 來初始化這些物件。  
如需其他資訊，請參閱 `SpringExampleConfiguration.xml`、`SpringExample.java` 和 `ExampleConfiguration.java` 節的 `ExampleCommon.java`、[搭配 Amazon SQS 標準佇列使用 JMS 的工作 Java 範例](sqs-jms-code-examples.md) 的其他說明類別。

如需傳送和接收物件的完整範例，請參閱 [TextMessageSender.java](sqs-jms-code-examples.md#example-sender) 和 [SyncMessageReceiver.java](sqs-jms-code-examples.md#example-synchronous-message-receiver)。

## 異步接收訊息
<a name="receive-messages-asynchronously"></a>

在 [使用 Amazon SQS Java Messaging Library](#getting-started) 的範例中，訊息會傳送到 `MyQueue` 並同步接收。

以下範例顯示的是如何透過接聽程式異步接收訊息。

1. 實作 `MessageListener` 介面。

   ```
   class MyListener implements MessageListener {
    
       @Override
       public void onMessage(Message message) {
           try {
               // Cast the received message as TextMessage and print the text to screen.
               System.out.println("Received: " + ((TextMessage) message).getText());
           } catch (JMSException e) {
               e.printStackTrace();
           }
       }
   }
   ```

   收到訊息時，即會呼叫 `MessageListener` 介面的 `onMessage` 方法。在此接聽程式的實作中，會將儲存在訊息中的文字列印出來。

1. 消費者端不會明確地呼叫 `receive` 方法，而是將消費者的訊息接聽程式設定為 `MyListener` 實作的執行個體。主執行緒會等待一秒。

   ```
   // Create a consumer for the 'MyQueue'.
   MessageConsumer consumer = session.createConsumer(queue);
    
   // Instantiate and set the message listener for the consumer.
   consumer.setMessageListener(new MyListener());
    
   // Start receiving incoming messages.
   connection.start();
    
   // Wait for 1 second. The listener onMessage() method is invoked when a message is received.
   Thread.sleep(1000);
   ```

接下來的步驟與 [使用 Amazon SQS Java Messaging Library](#getting-started) 範例相同。如需異步消費者的完整資訊，請參閱 `AsyncMessageReceiver.java` 的 [搭配 Amazon SQS 標準佇列使用 JMS 的工作 Java 範例](sqs-jms-code-examples.md)。

此範例的輸出結果類似如下：

```
JMS Message ID:8example-588b-44e5-bbcf-d816example2
Received: Hello World!
```

## 使用用戶端認可模式
<a name="using-client-acknowledge-mode"></a>

[使用 Amazon SQS Java Messaging Library](#getting-started) 中的範例使用 `AUTO_ACKNOWLEDGE` 模式，所有接收到的訊息會自動獲得認可 (因此會從底層的 Amazon SQS 佇列刪除)。

1. 若要明確在處理訊息後予以認可，則必須建立使用 `CLIENT_ACKNOWLEDGE` 模式的工作階段。

   ```
   // Create the non-transacted session with CLIENT_ACKNOWLEDGE mode.
   Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
   ```

1. 收到訊息後，會顯示訊息再明確予以認可。

   ```
   // Cast the received message as TextMessage and print the text to screen. Also acknowledge the message.
   if (receivedMessage != null) {
       System.out.println("Received: " + ((TextMessage) receivedMessage).getText());
       receivedMessage.acknowledge();
       System.out.println("Acknowledged: " + message.getJMSMessageID());
   }
   ```
**注意**  
在此模式中，當訊息受到認可，所有在此之前收到的訊息也會預設為認可。舉例而言，若收到 10 則訊息，而只有第 10 則訊息受到認可 (按訊息接收順序)，則之前的九則訊息也會受到認可。

接下來的步驟與 [使用 Amazon SQS Java Messaging Library](#getting-started) 範例相同。如需異步消費者用戶端認可模式的完整範例，請參閱 `SyncMessageReceiverClientAcknowledge.java` 的 [搭配 Amazon SQS 標準佇列使用 JMS 的工作 Java 範例](sqs-jms-code-examples.md)。

此範例的輸出結果類似如下：

```
JMS Message ID:4example-aa0e-403f-b6df-5e02example5
Received: Hello World!
Acknowledged: ID:4example-aa0e-403f-b6df-5e02example5
```

## 使用無順序認可模式
<a name="using-unordered-acknowledge-mode"></a>

當使用 `CLIENT_ACKNOWLEDGE` 模式時，受到明確認可的訊息之前所有接收到的訊息均會自動受到認可。如需詳細資訊，請參閱 [使用用戶端認可模式](#using-client-acknowledge-mode)。

Amazon SQS Java 訊息程式庫提供了另一種認可模式。使用 `UNORDERED_ACKNOWLEDGE` 模式時，所有接收的訊息必須明確受到用戶端個別認可，無論接收順序。若要這樣做，請建立 `UNORDERED_ACKNOWLEDGE` 模式的工作階段。

```
// Create the non-transacted session with UNORDERED_ACKNOWLEDGE mode.
Session session = connection.createSession(false, SQSSession.UNORDERED_ACKNOWLEDGE);
```

其他步驟與 [使用用戶端認可模式](#using-client-acknowledge-mode) 範例相同。如需同步消費者 `UNORDERED_ACKNOWLEDGE` 模式的完整資訊，請參閱 `SyncMessageReceiverUnorderedAcknowledge.java`。

此範例的輸出結果類似如下：

```
JMS Message ID:dexample-73ad-4adb-bc6c-4357example7
Received: Hello World!
Acknowledged: ID:dexample-73ad-4adb-bc6c-4357example7
```