

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

# ActiveMQ 教程
<a name="activemq-on-amazon-mq"></a>

以下教程介绍如何创建和连接到 ActiveMQ 代理。要使用 ActiveMQ Java 示例代码，您必须安装 [Java 标准版开发工具包](https://www.oracle.com/technetwork/java/javase/downloads/index.html)并对代码进行一些更改。

**Topics**
+ [Creating and Configuring a Network of Brokers](amazon-mq-creating-configuring-network-of-brokers.md)
+ [Connecting a Java application to your broker](amazon-mq-connecting-application.md)
+ [将 ActiveMQ 代理与 LDAP 集成](security-authentication-authorization.md)
+ [Connect your Amazon MQ for ActiveMQ broker to Lambda](#activemq-connect-to-lambda)
+ [创建 ActiveMQ 代理用户](amazon-mq-listing-managing-users.md)
+ [编辑 ActiveMQ 代理用户](edit-existing-user-console.md)
+ [删除 ActiveMQ 代理用户](delete-existing-user-console.md)
+ [Working Java Example](amazon-mq-working-java-example.md)

# 创建和配置 Amazon MQ 代理网络
<a name="amazon-mq-creating-configuring-network-of-brokers"></a>

*代理网络*由多个同时活动的[单实例代理](amazon-mq-broker-architecture.md#single-broker-deployment)或[主动/备用代理](amazon-mq-broker-architecture.md#active-standby-broker-deployment)组成。在本教程中，您将了解如何使用*源和接收器*拓扑来创建一个具有两个代理的代理网络。

有关概念概述和详细配置信息，请参阅以下内容：
+ [Amazon MQ 代理网络](network-of-brokers.md)
+ [正确配置您的代理网络](best-practices-activemq.md#network-of-brokers-configure-correctly)
+ `networkConnector`
+ `networkConnectionStart异步`
+ ActiveMQ 文档中的[代理网络](http://activemq.apache.org/networks-of-brokers.html)

您可以使用 Amazon MQ 控制台创建 Amazon MQ 代理网络。因为您可以开始并行创建这两个代理，所以此过程大约需要 15 分钟。

**Topics**
+ [先决条件](#creating-configuring-network-of-brokers-create-brokers)
+ [Configure the Brokers in a Network](#creating-configuring-network-of-brokers-allow-traffic)
+ [Configure Network Connectors for Your Broker](#creating-configuring-network-of-brokers-configure-network-connectors)
+ [Next Steps: Test the Network of Brokers](#creating-configuring-network-of-brokers-test)

## 先决条件
<a name="creating-configuring-network-of-brokers-create-brokers"></a>

要创建代理网络，您必须具备以下条件：
+ 两个或多个同时处于活动状态的代理（在本教程中命名为 `MyBroker1` 和 `MyBroker2`）。有关创建代理的更多信息，请参阅[入门：创建并连接 ActiveMQ 代理](getting-started-activemq.md)。
+ 这两个代理必须位于同一 VPC 中或处于对等状态。 VPCs有关更多信息 VPCs，请参阅[什么是 Amazon VPC？](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html) 在 *Amazon VPC 用户指南*和[什么是 VPC 对等互连](https://docs.aws.amazon.com/vpc/latest/peering/Welcome.html)？ 在《*亚马逊 VPC 对等互连指南》*中。
**重要**  
如果您没有默认 VPC、子网或安全组，则必须先创建它们。有关更多信息，请参阅《Amazon VPC 用户指南》**中的以下内容：  
[创建默认 VPC](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html#create-default-vpc)
[创建默认子网](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html#create-default-subnet)
[正在创建安全组](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#CreatingSecurityGroups)
+ 两个用户对两个代理程序具有相同的登录凭证。有关创建用户的更多信息，请参见 [创建 ActiveMQ 代理用户](amazon-mq-listing-managing-users.md)。
**注意**  
将 LDAP 身份验证与代理网络集成时，请确保该用户既作为 ActiveMQ 代理，也作为 LDAP 用户存在。

以下示例使用两个[单实例代理](amazon-mq-broker-architecture.md#single-broker-deployment)。但是，您可以使用[主动/备用代理](amazon-mq-broker-architecture.md#active-standby-broker-deployment)或代理部署模式的组合来创建代理网络。

## 步骤 1：允许代理之间的流量
<a name="creating-configuring-network-of-brokers-allow-traffic"></a>

创建代理后，必须允许它们之间的流量。

1. 在 [Amazon MQ 控制台](https://console.aws.amazon.com/amazon-mq/)上，在第 **MyBroker2** 页的 “**详细信息**” 部分的 “**安全和网络**” 下，选择您的安全组的名称或。![\[Pencil icon indicating an edit or modification action.\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/amazon-mq-tutorials-broker-details-link.png)

   此时将显示 EC2 Dashboard 的 **Security Groups (安全组)** 页面。

1. 从安全组列表中，选择您的安全组。

1. 在页面底部，选择 **Inbound (入站)**，然后选择 **Edit (编辑)**。

1. 在**编辑入站规则**对话框中，为 OpenWire 终端节点添加规则。

   1. 选择**添加规则**。

   1. 对于 **Type (类型)**，选择 **Custom TCP (自定义 TCP)**。

   1. 在 “**端口范围**” 中，键入 OpenWire 端口 (`61617`)。

   1. 请执行以下操作之一：
      + 如果您想要限制访问特定 IP 地址，对于 **Source (源)**，请将 **Custom (自定义)** 选定，然后输入主机的 IP 地址 `MyBroker1`，然后输入 `/32`。（这会将 IP 地址转换为有效的 CIDR 记录）。有关更多信息，请参阅[弹性网络接口](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html)。
**提示**  
要检索 `MyBroker1` 的 IP 地址，请在 [Amazon MQ 控制台](https://console.aws.amazon.com/amazon-mq/)上，选择代理的名称并导航到 **Details (详细信息)** 部分。
      + 如果所有代理都是私有的，并且属于相同的 VPC，则对于 **Source (源)**，请将 **Custom (自定义)** 选定，然后键入要编辑的安全组的 ID。
**注意**  
对于公有代理，您必须使用 IP 地址限制访问。

   1. 选择**保存**。

      您的代理现在可以接受入站连接。

## 步骤 2：为您的代理配置网络连接器
<a name="creating-configuring-network-of-brokers-configure-network-connectors"></a>

在允许代理之间的流量后，必须为其中一个代理配置网络连接器。

1. 编辑代理 `MyBroker1` 的配置修订。

   1. 在 **MyBroker1** 页上，选择**编辑**。

   1. 在 **“编辑 MyBroker 1”** 页面的 “**配置**” 部分，选择 “**查看**”。

      将会显示配置所使用的代理引擎类型和版本（例如，**Apache ActiveMQ 5.15.0**）。

   1. 在 **Configuration details** 选项卡上，会显示配置修订号、描述和 XML 格式的代理配置。

   1. 选择 **Edit configuration (编辑配置)**。

   1. 在配置文件的底部，取消注释 `<networkConnectors>` 部分并包含以下信息：
      + 网络连接器的 `name`。
      + 两个代理共有的 [ActiveMQ Web 控制台`username`](#creating-configuring-network-of-brokers-create-brokers)。
      + 启用 `duplex` 连接。
      + 请执行以下操作之一：
        + 如果您要将代理连接到单实例代理，请使用`static:`前缀和 OpenWire 终端节点`uri`。`MyBroker2`例如：

          ```
          <networkConnectors>
            <networkConnector name="connector_1_to_2" userName="myCommonUser" duplex="true"
              uri="static:(ssl://b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9-1.mq.us-east-2.amazonaws.com:61617)"/>
          </networkConnectors>
          ```
        + 如果您要将代理连接到活动/备用代理，请使用带有以下查询参数的两个代理`uri`的`static+failover`传输和 OpenWire终端节点。`?randomize=false&maxReconnectAttempts=0`例如：

          ```
          <networkConnectors>
            <networkConnector name="connector_1_to_2" userName="myCommonUser" duplex="true"
              uri="static:(failover:(ssl://b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9-1.mq.us-east-2.amazonaws.com:61617,
              ssl://b-9876l5k4-32ji-109h-8gfe-7d65c4b132a1-2.mq.us-west-2.amazonaws.com:61617)?randomize=false&amp;maxReconnectAttempts=0)"/>
          </networkConnectors>
          ```
**注意**  
不要包含 ActiveMQ 用户的登录凭证。

   1. 选择**保存**。

   1. 在 **Save revision (保存修订)** 对话框中，键入 `Add network of brokers connector for MyBroker2`。

   1. 选择 **Save (保存)** 以保存配置的新修订。

1. 编辑 `MyBroker1` 以将最新的配置修订设置为立即应用。

   1. 在 **MyBroker1** 页上，选择**编辑**。

   1. 在 **“编辑 MyBroker 1**” 页面的 “**配置**” 部分，选择 “**计划修改**”。

   1. 在 **Schedule broker modifications (计划代理修改)** 部分中，选择 **Immediately (立即)** 应用修改。

   1. 选择**应用**。

      `MyBroker1` 会重新启动，而且会应用您的配置修订。

   将会创建代理网络。

## 后续步骤
<a name="creating-configuring-network-of-brokers-test"></a>

配置代理网络后，可以通过生成和使用消息来测试它。

**重要**  
确保在端口 8162（*用于 ActiveMQ Web 控制台）和端口 61617（用于端点）`MyBroker1`上为代理启用来自本地计算机*[的入站连接](amazon-mq-working-java-example.md#quick-start-allow-inbound-connections)。 OpenWire  
您可能还需要调整安全组设置，以允许创建者和使用者连接到代理网络。

1. 在 [Amazon MQ 控制台](https://console.aws.amazon.com/amazon-mq/)上，导航到 **Connections (连接)** 部分，记下代理 `MyBroker1` 的 ActiveMQ Web 控制台终端节点。

1. 导航到代理 `MyBroker1` 的 ActiveMQ Web 控制台。

1. 要验证网桥是否已连接，请选择 **Network (网络)**。

   在**网络桥接**部分，`MyBroker2` 的名称和地址列在**远程代理**和**远程地址**列中。

1. 从任何可以访问代理 `MyBroker2` 的计算机上，创建一个使用者。例如：

   ```
   activemq consumer --brokerUrl "ssl://b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9-1.mq.us-east-2.amazonaws.com:61617" \
   	--user commonUser \
   	--password myPassword456 \
   	--destination queue://MyQueue
   ```

   使用者连接到的 OpenWire 终端节点`MyBroker2`并开始使用队列中的消息`MyQueue`。

1. 从任何可以访问代理 `MyBroker1` 的计算机上，创建一个创建者并发送一些消息。例如：

   ```
   activemq producer --brokerUrl "ssl://b-9876l5k4-32ji-109h-8gfe-7d65c4b132a1-1.mq.us-east-2.amazonaws.com:61617" \
   	--user commonUser \
   	--password myPassword456 \
   	--destination queue://MyQueue \
   	--persistent true \
   	--messageSize 1000 \
   	--messageCount 10000
   ```

   生产者连接到的 OpenWire 终端节点，`MyBroker1`并开始生成要排队的持久消息`MyQueue`。

# 将 Java 应用程序连接到您的 Amazon MQ 代理
<a name="amazon-mq-connecting-application"></a>

创建 Amazon MQ ActiveMQ 代理后，您可以将应用程序连接到该代理。以下示例演示如何使用 Java Message Service（JMS）创建代理连接、创建队列以及发送消息。有关完整的可用 Java 示例，请参阅[将 Java Message Service（JMS）与 ActiveMQ 配合使用的有效示例](amazon-mq-working-java-example.md)。

您可以使用[各种 ActiveMQ 客户端](http://activemq.apache.org/cross-language-clients.html)连接到 ActiveMQ 代理。我们建议使用 [ActiveMQ 客户端](https://mvnrepository.com/artifact/org.apache.activemq/activemq-client)。

**Topics**
+ [先决条件](#connect-application-prerequisites-tutorial)
+ [创建消息创建者并发送消息](#create-producer-send-message-tutorial)
+ [创建消息使用者并接收消息](#create-consumer-receive-message-tutorial)

## 先决条件
<a name="connect-application-prerequisites-tutorial"></a>

### 启用 VPC 属性
<a name="connect-application-enable-vpc-attributes-tutorial"></a>

要确保您的代理可以在您的 VPC 中访问，您必须启用 `enableDnsHostnames` 和 `enableDnsSupport` VPC 属性。有关更多信息，请参阅《Amazon VPC 用户指南》**中的 [VPC 中的 DNS Support](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html#vpc-dns-support)。

### 启用入站连接
<a name="connect-application-allow-inbound-connections-tutorial"></a>

接下来，为您的应用程序启用入站连接。

1. 登录 [Amazon MQ 控制台](https://console.aws.amazon.com/amazon-mq/)。

1. 从经纪人列表中，选择您的经纪商的名称（例如 **MyBroker**）。

1. 在该***MyBroker***页面的 “**连接**” 部分，记下代理的 Web 控制台 URL 和线级协议的地址和端口。

1. 在 **Details (详细信息)** 部分的 **Security and network (安全与网络)** 下，选择您的安全组名称或 ![\[Pencil icon indicating an edit or modification action.\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/amazon-mq-tutorials-broker-details-link.png)。

   此时将显示 EC2 Dashboard 的 **Security Groups (安全组)** 页面。

1. 从安全组列表中，选择您的安全组。

1. 在页面底部，选择 **Inbound (入站)**，然后选择 **Edit (编辑)**。

1. 在 **Edit inbound rules (编辑入站规则)** 对话框中，为希望公开访问的每个 URL 或终端节点添加规则（以下示例显示如何为代理 Web 控制台执行此操作。

   1. 选择**添加规则**。

   1. 对于 **Type (类型)**，选择 **Custom TCP (自定义 TCP)**。

   1. 对于 **Port Range (端口范围)**，键入 Web 控制台端口（`8162`）。

   1. 对于 **Source (源)**，选择 **Custom (自定义)**，然后键入您希望能够访问 Web 控制台的系统的 IP 地址（例如 `192.0.2.1`)。

   1. 选择**保存**。

      您的代理现在可以接受入站连接。

### 添加 Java 依赖项
<a name="connect-application-java-dependencies-tutorial"></a>

将 `activemq-client.jar` 和 `activemq-pool.jar` 程序包添加到 Java 类路径中。以下示例说明了 Maven 项目的 `pom.xml` 文件中的这些依赖关系。

```
<dependencies>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-client</artifactId>
        <version>5.15.16</version>
    </dependency>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-pool</artifactId>
        <version>5.15.16</version>
    </dependency>
</dependencies>
```

有关 `activemq-client.jar` 的更多信息，请参阅 Apache ActiveMQ 文档中的[初始配置](http://activemq.apache.org/initial-configuration.html)。

**重要**  
在以下示例代码中，生产者和使用者在单个线程中运行。对于生产系统（或测试代理实例故障转移），请确保您的创建者和使用者在单独的主机或线程上运行。

## 创建消息创建者并发送消息
<a name="create-producer-send-message-tutorial"></a>

 使用以下说明创建消息生产者并接收消息。

1. 使用代理的终端节点为消息创建者创建 JMS 池连接工厂，然后针对该工厂调用 `createConnection` 方法。
**注意**  
对于 active/standby 代理商，Amazon MQ 提供了两个 ActiveMQ Web 控制台 URLs，但一次只有一个 URL 处于活动状态。同样，Amazon MQ 为每个线级协议提供两个终端节点，但每次每对中只有一个终端节点处于活动状态。`-1` 和 `-2` 后缀表示冗余对。有关更多信息，请参阅 [Amazon MQ for ActiveMQ 代理的部署选项](amazon-mq-broker-architecture.md)）。  
对于线路级协议端点，您应允许您的应用程序使用[失效转移传输](http://activemq.apache.org/failover-transport-reference.html)连接到任一端点。

   ```
   // Create a connection factory.
   final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(wireLevelEndpoint);
   
   // Pass the sign-in credentials.
   connectionFactory.setUserName(activeMqUsername);
   connectionFactory.setPassword(activeMqPassword);
   
   // Create a pooled connection factory.
   final PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory();
   pooledConnectionFactory.setConnectionFactory(connectionFactory);
   pooledConnectionFactory.setMaxConnections(10);
   
   // Establish a connection for the producer.
   final Connection producerConnection = pooledConnectionFactory.createConnection();
   producerConnection.start(); 
   
   // Close all connections in the pool.
   pooledConnectionFactory.clear();
   ```
**注意**  
消息创建者应始终使用 `PooledConnectionFactory` 类。有关更多信息，请参阅 [始终使用连接池](best-practices-activemq.md#always-use-connection-pooling)。

1. 创建一个会话，一个名为 `MyQueue` 的队列和消息创建者。

   ```
   // Create a session.
   final Session producerSession = producerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
   
   // Create a queue named "MyQueue".
   final Destination producerDestination = producerSession.createQueue("MyQueue");
   
   // Create a producer from the session to the queue.
   final MessageProducer producer = producerSession.createProducer(producerDestination);
   producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
   ```

1. 创建消息字符串 `"Hello from Amazon MQ!"`，然后发送消息。

   ```
   // Create a message.
   final String text = "Hello from Amazon MQ!";
   TextMessage producerMessage = producerSession.createTextMessage(text);
   
   // Send the message.
   producer.send(producerMessage);
   System.out.println("Message sent.");
   ```

1. 清理创建者。

   ```
   producer.close();
   producerSession.close();
   producerConnection.close();
   ```

## 创建消息使用者并接收消息
<a name="create-consumer-receive-message-tutorial"></a>

 使用以下说明创建消息生产者并接收消息。

1. 使用代理的终端节点为消息创建者创建 JMS 连接工厂，然后针对该工厂调用 `createConnection` 方法。

   ```
   // Create a connection factory.
   final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(wireLevelEndpoint);
   
   // Pass the sign-in credentials.
   connectionFactory.setUserName(activeMqUsername);
   connectionFactory.setPassword(activeMqPassword);
   
   // Establish a connection for the consumer.
   final Connection consumerConnection = connectionFactory.createConnection();
   consumerConnection.start();
   ```
**注意**  
消息使用者*绝不* 应使用 `PooledConnectionFactory` 类。有关更多信息，请参阅 [始终使用连接池](best-practices-activemq.md#always-use-connection-pooling)。

1. 创建一个会话，一个名为 `MyQueue` 的队列和消息使用者。

   ```
   // Create a session.
   final Session consumerSession = consumerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
   
   // Create a queue named "MyQueue".
   final Destination consumerDestination = consumerSession.createQueue("MyQueue");
   
   // Create a message consumer from the session to the queue.
   final MessageConsumer consumer = consumerSession.createConsumer(consumerDestination);
   ```

1. 开始等待消息,并在消息到达时收到消息。

   ```
   // Begin to wait for messages.
   final Message consumerMessage = consumer.receive(1000);
   
   // Receive the message when it arrives.
   final TextMessage consumerTextMessage = (TextMessage) consumerMessage;
   System.out.println("Message received: " + consumerTextMessage.getText());
   ```
**注意**  
与 AWS 消息服务（例如 Amazon SQS）不同，消费者经常与经纪人建立联系。

1. 关闭使用者、会话和连接。

   ```
   consumer.close();
   consumerSession.close();
   consumerConnection.close();
   ```

# 将 ActiveMQ 代理与 LDAP 集成
<a name="security-authentication-authorization"></a>

**重要**  
Amazon MQ 不支持由私人 CA 签发的服务器证书。

您可以使用以下启用 TLS 的协议来访问 ActiveMQ 代理：
+ [AMQP](http://activemq.apache.org/amqp.html)
+ [MQTT](http://activemq.apache.org/mqtt.html)
+ MQTT 结束了 [WebSocket](http://activemq.apache.org/websockets.html)
+ [OpenWire](http://activemq.apache.org/openwire.html)
+ [STOMP](http://activemq.apache.org/stomp.html)
+ 大吃一惊 WebSocket

Amazon MQ 提供以下用户权限管理选项：本机 ActiveMQ 身份验证和 LDAP 身份验证以及授权。有关与 ActiveMQ 用户名和密码相关的限制的信息，请参阅[Users](amazon-mq-limits.md#activemq-user-limits)。

要授权 ActiveMQ 用户和组使用队列和主题，必须[编辑您的代理的配置](amazon-mq-creating-applying-configurations.md)。Amazon MQ 使用 ActiveMQ 的[简单身份验证插件](http://activemq.apache.org/security.html#Security-SimpleAuthenticationPlugin)来限制读取和写入到目标。有关详细信息和示例，请参阅[始终配置授权映射](using-amazon-mq-securely.md#always-configure-authorization-map)和 `authorizationEntry`。

**注意**  
目前，Amazon MQ 不支持客户端证书身份验证。

**Topics**
+ [将 LDAP 与 ActiveMQ 集成](#integrate-ldap)
+ [先决条件](#ldap-prerequisites)
+ [LDAP 入门](#ldap-get-started)
+ [LDAP 集成的工作方式](#ldap-support-details)

## 将 LDAP 与 ActiveMQ 集成
<a name="integrate-ldap"></a>

您可以通过存储在轻型目录访问协议（LDAP）服务器中的凭证对 Amazon MQ 用户进行身份验证。您还可以添加、删除和修改 Amazon MQ 用户，并借此为主题和队列分配权限。创建、更新和删除代理等管理操作仍然需要 IAM 凭证，并且未与 LDAP 集成。

希望使用 LDAP 服务器简化和集中化 Amazon MQ 代理身份验证和授权的客户可以使用此功能。将所有用户凭证保留在 LDAP 服务器中，为存储和管理这些凭证提供了一个中心位置，从而节省了时间和精力。

Amazon MQ 使用 Apache ActiveMQ JAAS 插件来提供 LDAP 支持。该插件支持的任何 LDAP 服务器，如 Microsoft Active Directory 或 OpenLDAP，还得到了 Amazon MQ 的支持。有关插件的更多信息，请参阅 Active MQ 文档的 [Security (安全)](https://activemq.apache.org/security) 部分。

除用户外，您还可以通过 LDAP 服务器指定对特定组或用户的主题和队列的访问权限。您可以通过在 LDAP 服务器中创建表示主题和队列的条目，然后为特定 LDAP 用户或组分配权限来实现此目的。然后，您可以将代理配置为从 LDAP 服务器中检索授权数据。

**重要**  
 使用 LDAP 时，认证不区分大小写，但授权对您的用户名区分大小写。

## 先决条件
<a name="ldap-prerequisites"></a>

在将 LDAP 支持添加到新的或现有的 Amazon MQ 代理之前，您必须设置一个服务账户。启动与 LDAP 服务器的连接需要此服务账户，并且必须具有正确的权限才能建立此连接。此服务账户将为您的代理设置 LDAP 身份验证。任何连续的客户端连接都将通过同一连接进行身份验证。

服务账户是 LDAP 服务器中有权启动连接的账户。这是一个标准的 LDAP 要求，您只能提供一次服务账户凭证。设置连接后，所有未来的客户端连接都将通过 LDAP 服务器进行身份验证。您的服务账户凭证以加密形式安全存储，只有 Amazon MQ 才能访问。

要与 ActiveMQ 集成，LDAP 服务器上需要一个特定的目录信息树（DIT）。有关可清楚显示此结构的 `ldif` 文件示例，请参阅 ActiveMQ 文档 [Security (安全)](https://activemq.apache.org/security) 部分中的*将以下 LDIF 文件导入 LDAP 服务器*。

## LDAP 入门
<a name="ldap-get-started"></a>

要开始操作，在创建新的 Amazon MQ 或编辑现有代理实例时，请导航到 Amazon MQ 控制台，并选择 **LDAP authentication and authorization (LDAP 身份验证和授权)**。

提供有关服务账户的以下信息：
+ **完全限定域名**：要向其发出身份验证和授权请求的 LDAP 服务器的位置。
**注意**  
您提供的 LDAP 服务器的完全限定域名不能包含协议或端口号。Amazon MQ 会在完全限定域名前加上协议 `ldaps`，并将附加端口号 `636`。  
例如，如果您提供完全限定域 `example.com`，Amazon MQ 将使用以下 URL 访问您的 LDAP 服务器：`ldaps://example.com:636`。  
为了使代理主机能够与 LDAP 服务器成功通信，完全限定域名必须可以公开解析。要保持 LDAP 服务器的私有和安全性，请在服务器入站规则中限制入站流量，以便仅允许来自代理 VPC 内的流量。
+ **服务账户用户名**：用于执行与 LDAP 服务器初始绑定的用户的可分辨名称。
+ **服务账户密码**：执行初始绑定的用户的密码。

下图突出显示了提供这些详细信息的位置。

![\[指定 LDAP 服务账户详细信息的位置。\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/active-mq-ldap-service-account.png)


在 **LDAP login configuration (LDAP 登录配置)** 部分中，提供以下必要信息：
+ **用户基础**：将为用户搜索的目录信息树（DIT）中的节点的可分辨名称。
+ **用户搜索匹配**：LDAP 搜索筛选条件，将用于在 `userBase` 中查找用户。客户端的用户名将替换搜索筛选条件中的 `{0}` 占位符。有关更多信息，请参阅[身份验证](#ldap-authentication)和[Authorization](#ldap-authorization)。
+ **角色基础**：将为角色搜索的 DIT 中的节点的可分辨名称。角色可以配置为目录中的显式 LDAP 组条目。典型角色条目可能由角色名称的一个属性（例如**公用名（CN）**）和另一个属性（例如 `member`）组成，其中的值表示属于角色组的用户的可分辨名称或用户名。例如，鉴于组织部门 `group`，您可以提供以下可分辨名称：`ou=group,dc=example,dc=com`。
+ **角色搜索匹配**：用于在 `roleBase` 中查找角色的 LDAP 搜索筛选条件。`userSearchMatching` 匹配的用户的可分辨名称将替换为搜索筛选条件中的 `{0}` 占位符。客户端的用户名将替换为 `{1}` 占位符。例如，如果目录中的角色条目包含名为 `member` 的属性（包含该角色中所有用户的用户名），则可以提供以下搜索筛选条件：`(member:=uid={1})`。

 下图突出显示了指定这些详细信息的位置。

![\[指定 LDAP 登录详细信息的位置。\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/active-mq-ldap-login-configuration.png)


在 **Optional settings (可选设置)** 部分中，您可以提供以下可选信息：
+ **用户角色名称**：用户组成员资格的用户目录条目中 LDAP 属性的名称。在某些情况下，用户角色可能由用户目录条目中属性的值来标识。`userRoleName` 选项允许您提供此属性的名称。例如，让我们考虑以下用户条目：

  ```
  dn: uid=jdoe,ou=user,dc=example,dc=com
  objectClass: user
  uid: jdoe
  sn: jane
  cn: Jane Doe
  mail: j.doe@somecompany.com
  memberOf: role1
  userPassword: password
  ```

  要为上述示例提供正确的 `userRoleName`，您需要指定 `memberOf` 属性。如果身份验证成功，则会向用户分配角色 `role1`。
+ **角色名称**：角色条目中的组名属性，值为该角色的名称。例如，您可以为组条目的**通用名称**指定 `cn`。如果身份验证成功，则会为用户分配其作为成员的每个角色条目的 `cn` 属性值。
+ **用户搜索子树**：定义 LDAP 用户搜索查询的范围。如果为 true，则搜索范围设置为由 `userBase` 定义的节点下的整个子树。
+ **角色搜索子树**：定义 LDAP 角色搜索查询的范围。如果为 true，则搜索范围设置为由 `roleBase` 定义的节点下的整个子树。

下图突出显示了指定这些可选设置的位置。

![\[Optional settings for LDAP attributes and search scope in role search matching.\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/amazon-mq-active-ldap-optional-settings.png)


## LDAP 集成的工作方式
<a name="ldap-support-details"></a>

您可以将集成分为两大类：身份验证结构和授权结构。

### 身份验证
<a name="ldap-authentication"></a>

对于身份验证，客户端凭证必须有效。这些凭证针对 LDAP 服务器的用户基础中的用户进行验证。

提供给 ActiveMQ 代理的用户基础必须指向 DIT 中存储用户的 LDAP 服务器中的节点。例如，如果您正在使用 AWS Managed Microsoft AD，并且有域组件`corp``example``com`、和，并且在这些组件中包含组织单位`corp`和`Users`，则应使用以下内容作为用户群：

```
OU=Users,OU=corp,DC=corp,DC=example,DC=com
```

ActiveMQ 代理将在 DIT 中的此位置搜索用户，以便对发给代理的客户端连接请求进行身份验证。

![\[搜索用户的位置\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/active-mq-ldap-structure.png)


由于 ActiveMQ 源代码对用户的属性名称硬编码为 `uid`，您必须确保每个用户都设置了此属性。为简单起见，您可以使用用户的连接用户名。有关更多信息，请参阅 [activemq](https://github.com/apache/activemq/blob/c3d9b388e4f1fe73e348bf466122fe6862e064a0/activemq-broker/src/main/java/org/apache/activemq/security/SimpleCachedLDAPAuthorizationMap.java#L89) 源代码和[在 Windows Server 2016（及后续）版本的 Active Directory 用户和计算机中配置 ID 映射](https://www.ibm.com/support/knowledgecenter/en/STXKQY_5.0.3/com.ibm.spectrum.scale.v5r03.doc/bl1adm_confidmapaduc.htm)。

要为特定用户启用 ActiveMQ 控制台访问，请确保他们属于 `amazonmq-console-admins` 组。

### Authorization
<a name="ldap-authorization"></a>

对于授权，权限搜索基础在代理配置中指定。授权通过代理的 `activemq.xml` 配置文件中的 `cachedLdapAuthorizationMap` 元素在每个目标（或通配符，目标集）上完成。有关更多信息，请参阅[缓存 LDAP 授权模块](https://activemq.apache.org/cached-ldap-authorization-module)。

**注意**  
为了能够使用代理`activemq.xml`配置文件中的`cachedLDAPAuthorizationMap`元素，您必须在通过[创建配置时选择 **LDAP 身份验证和授权**选项 AWS 管理控制台，或者通过](amazon-mq-creating-applying-configurations.md)设置[创建配置 AWS 管理控制台](amazon-mq-creating-applying-configurations.md)，或者在使用 Amazon MQ API 创建新配置`LDAP`时将[https://docs.aws.amazon.com//amazon-mq/latest/api-reference/configurations.html#configurations-model-authenticationstrategy](https://docs.aws.amazon.com//amazon-mq/latest/api-reference/configurations.html#configurations-model-authenticationstrategy)属性设置为。

您必须提供以下三个属性作为 `cachedLDAPAuthorizationMap` 元素的一部分：
+ `queueSearchBase`
+ `topicSearchBase`
+ `tempSearchBase`

**重要**  
为了防止敏感信息直接放置在代理的配置文件中，Amazon MQ 阻止以下属性在 `cachedLdapAuthorizationMap` 中使用：  
`connectionURL`
`connectionUsername`
`connectionPassword`
当您创建经纪商时，Amazon MQ 会使用您通过或您的 API 请求的[https://docs.aws.amazon.com//amazon-mq/latest/api-reference/brokers.html#brokers-prop-createbrokerinput-ldapservermetadata](https://docs.aws.amazon.com//amazon-mq/latest/api-reference/brokers.html#brokers-prop-createbrokerinput-ldapservermetadata)属性中提供的值来代替上述属性。 AWS 管理控制台

以下演示了 `cachedLdapAuthorizationMap` 的工作示例。

```
<authorizationPlugin>
    <map>
        <cachedLDAPAuthorizationMap
            queueSearchBase="ou=Queue,ou=Destination,ou=corp,dc=corp,dc=example,dc=com"
            topicSearchBase="ou=Topic,ou=Destination,ou=corp,dc=corp,dc=example,dc=com"
            tempSearchBase="ou=Temp,ou=Destination,ou=corp,dc=corp,dc=example,dc=com"
            refreshInterval="300000"
            legacyGroupMapping="false"
        />
    </map>
</authorizationPlugin>
```

这些值标识 DIT 中为每个目标类型指定权限的位置。因此，对于上面的示例 AWS Managed Microsoft AD，使用`corp``example`、和的相同域组件`com`，您可以指定一个名为的组织单位`destination`来包含所有目标类型。在该组织部门中，您将为 `queues`、`topics` 和 `temp` 目标分别创建一个。

这意味着您的队列搜索基础（为类型队列的目标提供授权信息）将在 DIT 中具有以下位置：

```
OU=Queue,OU=Destination,OU=corp,DC=corp,DC=example,DC=com
```

![\[队列搜索基础位置。\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/active-mq-ldap-queue-structure.png)


同样，主题和临时目标的权限规则将位于 DIT 中的同一级别：

```
OU=Topic,OU=Destination,OU=corp,DC=corp,DC=example,DC=com
OU=Temp,OU=Destination,OU=corp,DC=corp,DC=example,DC=com
```

在每个目标类型（队列、主题、临时）的组织部门中，可以提供通配符或特定目标名称。例如，若要为以前缀 DEMO.EVENTS.\$1. 开头的所有队列提供授权规则，您可以创建以下组织部门：

```
OU=DEMO.EVENTS.$,OU=Queue,OU=Destination,OU=corp,DC=corp,DC=example,DC=com
```

**注意**  
`DEMO.EVENTS.$` 组织部门位于 `Queue` 组织部门内。

有关 ActiveMQ 中通配符的更多信息，请参阅 [Wildcards (通配符)](https://activemq.apache.org/wildcards)

要为特定队列提供授权规则（如 DEMO.MYQUEUE），请指定类似以下内容：

```
OU=DEMO.MYQUEUE,OU=Queue,OU=Destination,OU=corp,DC=corp,DC=example,DC=com
```

![\[特定队列的授权规则\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/active-mq-ldap-authorization-rules.png)


### 安全组
<a name="ldap-security-groups"></a>

在每个表示目标或通配符的组织部门中，您必须创建三个安全组。与 ActiveMQ 中的所有权限一样，这些都是权限。read/write/admin有关每个权限允许用户执行哪些操作的更多信息，请参阅 ActiveMQ 文档中的[安全性](https://activemq.apache.org/security)。

您必须命名这些安全组 `read`、`write` 和 `admin`。在这些安全组中，您可以添加用户或组，他们将有权执行相关操作。对于每个通配符目标集或单个目标，您都需要这些安全组。

![\[安全组\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/active-mq-ldap-security-groups.png)


**注意**  
创建管理组时，将与组名称发生冲突。发生此冲突的原因是，Windows 2000 之前的旧式规则不允许组共享相同的名称，即使这些组位于 DIT 的不同位置。**Windows 2000** 之前版本文本框中的值对设置没有影响，但必须是全局唯一的。为了避免这一冲突，可以为每个 `admin` 组添加 `uuid` 后缀。  

![\[这是我的映像。\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/active-mq-ldap-admin-qualifier.png)


将用户添加到特定目标的 `admin` 安全组将允许用户创建和删除该主题。将他们添加到 `read` 安全组将使他们能够从目标读取，而将他们添加到 `write` 组则将使他们能够写入目标。

除了将单个用户添加到安全组权限之外，您还可以添加整个组。但是，由于 ActiveMQ 再次对组的属性名称进行硬编码，因此必须确保要添加的组具有对象类 `groupOfNames`，如 [activemq](https://github.com/apache/activemq/blob/c3d9b388e4f1fe73e348bf466122fe6862e064a0/activemq-broker/src/main/java/org/apache/activemq/security/SimpleCachedLDAPAuthorizationMap.java#L86) 源代码中所示。

要执行此操作，请遵循与用户 `uid` 相同的流程。请参阅[在 Windows Server 2016（及后续）版本的 Active Directory 用户和计算机中配置 ID 映射](https://www.ibm.com/support/knowledgecenter/en/STXKQY_5.0.3/com.ibm.spectrum.scale.v5r03.doc/bl1adm_confidmapaduc.htm)。

## 步骤 3：（可选）Connect 到 AWS Lambda 函数
<a name="activemq-connect-to-lambda"></a>

 AWS Lambda 可以连接并使用来自您的 Amazon MQ 代理的消息。当您将代理连接到 Lambda 时，可以创建[事件源映射](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventsourcemapping.html)，从队列中读取消息并[同步](https://docs.aws.amazon.com/lambda/latest/dg/invocation-sync.html)调用函数。您创建的事件源映射分批从您的代理中读取消息，并以 JSON 对象的形式将它们转换为 Lambda 负载。

**将您的代理连接到 Lambda 函数**

1. 将以下 IAM 角色权限添加到 Lambda 函数[执行角色](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html)。
   + [mq: DescribeBroker](https://docs.aws.amazon.com/amazon-mq/latest/api-reference/brokers-broker-id.html#brokers-broker-id-http-methods)
   + [ec2: CreateNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkInterface.html)
   + [ec2: DeleteNetworkInterface](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkInterface.html)
   + [ec2: DescribeNetworkInterfaces](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNetworkInterfaces.html)
   + [ec2: DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html)
   + [ec2: DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html)
   + [ec2: DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html)
   + [日志：CreateLogGroup](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogGroup.html)
   + [日志：CreateLogStream](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_CreateLogStream.html)
   + [日志：PutLogEvents](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html)
   + [秘密管理器：GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html)
**注意**  
如果没有必要的 IAM 权限，您的函数将无法从 Amazon MQ 资源中成功读取记录。

1.  （可选）如果您创建了一个没有公开可访问性的代理，则必须执行下面其中一项操作以允许 Lambda 连接到您的代理：
   +  为每个公有子网配置一个 NAT 网关。有关更多信息，请参阅《AWS Lambda 开发人员指南》**中的[VPC 连接函数的互联网和服务访问](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html#vpc-internet)。
   + 使用 VPC 终端节点在您的 Amazon Virtual Private Cloud（Amazon VPC）和 Lambda 之间创建连接。您的 Amazon VPC 还必须连接到 AWS Security Token Service (AWS STS) 和 Secrets Manager 终端节点。有关更多信息，请参阅《AWS Lambda 开发人员指南》**中的[为 Lambda 配置接口 VPC 终端节点](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc-endpoints.html)。

1.  使用 AWS 管理控制台为 Lambda 函数[配置代理作为事件源](https://docs.aws.amazon.com/lambda/latest/dg/with-mq.html#services-mq-eventsourcemapping)。您也可以使用该[https://docs.aws.amazon.com/cli/latest/reference/lambda/create-event-source-mapping.html](https://docs.aws.amazon.com/cli/latest/reference/lambda/create-event-source-mapping.html) AWS Command Line Interface 命令。

1.  为 Lambda 函数编写一些代码来处理从您的代理使用的消息。事件源映射检索的 Lambda 负载取决于代理的引擎类型。以下是适用于 Amazon MQ for ActiveMQ 队列的 Lambda 负载示例。
**注意**  
 在该示例中，`testQueue` 是队列的名称。

   ```
   {
     "eventSource": "aws:amq",
     "eventSourceArn": "arn:aws:mq:us-west-2:112556298976:broker:test:b-9bcfa592-423a-4942-879d-eb284b418fc8",
     "messages": {
       [
         {
           "messageID": "ID:b-9bcfa592-423a-4942-879d-eb284b418fc8-1---mq---us-west-2.amazonaws.com.rproxy.govskope.us-37557-1234520418293-4:1:1:1:1",
           "messageType": "jms/text-message",
           "data": "QUJDOkFBQUE=",
           "connectionId": "myJMSCoID",
           "redelivered": false,
           "destination": {
             "physicalname": "testQueue" 
           }, 
           "timestamp": 1598827811958,
           "brokerInTime": 1598827811958,
           "brokerOutTime": 1598827811959
         },
         {
           "messageID": "ID:b-9bcfa592-423a-4942-879d-eb284b418fc8-1---mq---us-west-2.amazonaws.com.rproxy.govskope.us-37557-1234520418293-4:1:1:1:1",
           "messageType":"jms/bytes-message",
           "data": "3DTOOW7crj51prgVLQaGQ82S48k=",
           "connectionId": "myJMSCoID1",
           "persistent": false,
           "destination": {
             "physicalname": "testQueue" 
           }, 
           "timestamp": 1598827811958,
           "brokerInTime": 1598827811958,
           "brokerOutTime": 1598827811959
         }
       ]
     }
   }
   ```

有关将 Amazon MQ 连接到 Lambda、Lambda 为 Amazon MQ 事件源提供支持的选项和事件源映射错误的更多信息，请参阅《AWS Lambda 开发人员指南》**中的[将 Lambda 与 Amazon MQ 结合使用](https://docs.aws.amazon.com/lambda/latest/dg/with-mq.html)。

# 创建 ActiveMQ 代理用户
<a name="amazon-mq-listing-managing-users"></a>

ActiveMQ *用户*是能够访问 ActiveMQ 代理的队列和主题的人或应用程序。您可以将用户配置为具有特定权限。例如，您可以允许某些用户访问 [ActiveMQ Web 控制台](http://activemq.apache.org/web-console.html)。

*组*是一个语义标签。您可以为用户分配组，并为组配置发送、接收和管理特定队列和主题的权限。

**注意**  
您无法独立于用户来配置组。在向组标签中添加至少一个用户时，将创建组标签；在从组标签中删除所有用户时，将删除组标签。

**注意**  
 ActiveMQ on Amazon MQ 中的 `activemq-webconsole` 组拥有所有队列和主题的管理权限。该组中的所有用户都有管理员访问权限。

以下示例演示如何使用 AWS 管理控制台创建、编辑和删除 Amazon MQ 代理用户。

## 创建新的 ActiveMQ 代理用户
<a name="create-new-user-console"></a>

1. 登录 [Amazon MQ 控制台](https://console.aws.amazon.com/amazon-mq/)。

1. 从经纪人列表中，选择您的经纪商名称（例如 **MyBroker**），然后选择**查看详情**。

   在该***MyBroker***页面的 “**用户**” 部分中，列出了该经纪商的所有用户。  
![\[Table showing two users with their console access and group information.\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/amazon-mq-tutorials-list-users.png)

1. 选择**创建用户**。

1. 在 **Create user (创建用户)** 对话框中，键入 **Username (用户名)** 和 **Password (密码)**。

1. (可选) 键入用户所属的组的名称，用逗号分隔 (例如：`Devs, Admins`)。

1. （可选）要使用户能够访问 [ActiveMQ Web 控制台](http://activemq.apache.org/web-console.html)，请选择 **ActiveMQ Web Console (ActiveMQ Web 控制台)**。

1. 选择**创建用户**。
**重要**  
对用户进行更改*不会*立即将更改应用于用户。要应用更改，必须等待下一维护时段或者[重启代理](amazon-mq-rebooting-broker.md)。

# 编辑 ActiveMQ 代理用户
<a name="edit-existing-user-console"></a>

 要编辑现有用户，请执行以下操作：

1. 登录 [Amazon MQ 控制台](https://console.aws.amazon.com/amazon-mq/)。

1. 从经纪人列表中，选择您的经纪商名称（例如 **MyBroker**），然后选择**查看详情**。

   在该***MyBroker***页面的 “**用户**” 部分中，列出了该经纪商的所有用户。  
![\[Table showing two users with their console access and group information.\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/amazon-mq-tutorials-list-users.png)

1. 选择您的登录凭证，然后选择**编辑**。

   将会显示 **Edit user (编辑用户)** 对话框。

1. （可选）键入新 **Password (密码)**。

1. (可选) 添加或删除用户所属的组的名称，用逗号分隔 (例如：`Managers, Admins`)。

1. （可选）要使用户能够访问 [ActiveMQ Web 控制台](http://activemq.apache.org/web-console.html)，请选择 **ActiveMQ Web Console (ActiveMQ Web 控制台)**。

1. 要保存对用户所做的更改，请选择 **Done (完成)**。
**重要**  
对用户进行更改*不会*立即将更改应用于用户。要应用更改，必须等待下一维护时段或者[重启代理](amazon-mq-rebooting-broker.md)。

# 删除 ActiveMQ 代理用户
<a name="delete-existing-user-console"></a>

 不再需要某个用户时，可以删除该用户。

1. 登录 [Amazon MQ 控制台](https://console.aws.amazon.com/amazon-mq/)。

1. 从经纪人列表中，选择您的经纪商名称（例如 **MyBroker**），然后选择**查看详情**。

   在该***MyBroker***页面的 “**用户**” 部分中，列出了该经纪商的所有用户。  
![\[Table showing two users with their console access and group information.\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/amazon-mq-tutorials-list-users.png)

1. 选择您的登录凭据（例如 ***MyUser***），然后选择 “**删除**”。

1. 要确认删除用户，请在 “**删除*MyUser*？”** 对话框中，选择 “**删除”**。
**重要**  
对用户进行更改*不会*立即将更改应用于用户。要应用更改，必须等待下一维护时段或者[重启代理](amazon-mq-rebooting-broker.md)。

# 将 Java Message Service（JMS）与 ActiveMQ 配合使用的有效示例
<a name="amazon-mq-working-java-example"></a>

以下示例演示如何以编程方式使用 ActiveMQ：
+ 示 OpenWire 例 Java 代码连接到代理、创建队列以及发送和接收消息。有关详细分解和说明，请参阅[将 Java 应用程序连接到您的 Amazon MQ 代理](amazon-mq-connecting-application.md)。
+ MQTT 示例 Java 代码可连接到代理、创建主题并发送和接收消息。
+ STOMP\$1WSS 示例 Java 代码可连接到代理、创建队列并发送和接收消息。

## 先决条件
<a name="quick-start-prerequisites"></a>

### 启用 VPC 属性
<a name="quick-start-enable-vpc-attributes"></a>

要确保您的代理可以在您的 VPC 中访问，您必须启用 `enableDnsHostnames` 和 `enableDnsSupport` VPC 属性。有关更多信息，请参阅《Amazon VPC 用户指南》**中的 [VPC 中的 DNS Support](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html#vpc-dns-support)。

### 启用入站连接
<a name="quick-start-allow-inbound-connections"></a>

 要以编程方式使用 Amazon MQ，必须使用入站连接。

1. 登录 [Amazon MQ 控制台](https://console.aws.amazon.com/amazon-mq/)。

1. 从经纪人列表中，选择您的经纪商的名称（例如 **MyBroker**）。

1. 在该***MyBroker***页面的 “**连接**” 部分，记下代理的 Web 控制台 URL 和线级协议的地址和端口。

1. 在 **Details (详细信息)** 部分的 **Security and network (安全与网络)** 下，选择您的安全组名称或 ![\[Pencil icon indicating an edit or modification action.\]](http://docs.aws.amazon.com/zh_cn/amazon-mq/latest/developer-guide/images/amazon-mq-tutorials-broker-details-link.png)。

   此时将显示 EC2 Dashboard 的 **Security Groups (安全组)** 页面。

1. 从安全组列表中，选择您的安全组。

1. 在页面底部，选择 **Inbound (入站)**，然后选择 **Edit (编辑)**。

1. 在 **Edit inbound rules (编辑入站规则)** 对话框中，为希望公开访问的每个 URL 或终端节点添加规则（以下示例显示如何为代理 Web 控制台执行此操作。

   1. 选择**添加规则**。

   1. 对于 **Type (类型)**，选择 **Custom TCP (自定义 TCP)**。

   1. 对于 **Port Range (端口范围)**，键入 Web 控制台端口（`8162`）。

   1. 对于 **Source (源)**，选择 **Custom (自定义)**，然后键入您希望能够访问 Web 控制台的系统的 IP 地址（例如 `192.0.2.1`)。

   1. 选择**保存**。

      您的代理现在可以接受入站连接。

### 添加 Java 依赖项
<a name="quick-start-java-dependencies"></a>

------
#### [ OpenWire ]

将 `activemq-client.jar` 和 `activemq-pool.jar` 程序包添加到 Java 类路径中。以下示例说明了 Maven 项目的 `pom.xml` 文件中的这些依赖关系。

```
<dependencies>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-client</artifactId>
        <version>5.15.16</version>
    </dependency>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-pool</artifactId>
        <version>5.15.16</version>
    </dependency>
</dependencies>
```

有关 `activemq-client.jar` 的更多信息，请参阅 Apache ActiveMQ 文档中的[初始配置](http://activemq.apache.org/initial-configuration.html)。

------
#### [ MQTT ]

将 `org.eclipse.paho.client.mqttv3.jar` 程序包添加到 Java 类路径中。以下示例说明了 Maven 项目的 `pom.xml` 文件中的这一依赖关系。

```
<dependencies>
                    <dependency>
                        <groupId>org.eclipse.paho</groupId>
                        <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
                        <version>1.2.0</version>
                    </dependency>                               
                    </dependencies>
```

有关 `org.eclipse.paho.client.mqttv3.jar` 的更多信息，请参阅 [Eclipse Paho Java 客户端](https://www.eclipse.org/paho/clients/java/)。

------
#### [ STOMP\$1WSS ]

将以下程序包添加到了 Java 类路径：
+ `spring-messaging.jar`
+ `spring-websocket.jar`
+ `javax.websocket-api.jar`
+ `jetty-all.jar`
+ `slf4j-simple.jar`
+ `jackson-databind.jar`

以下示例说明了 Maven 项目的 `pom.xml` 文件中的这些依赖关系。

```
<dependencies>
                    <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-messaging</artifactId>
                        <version>5.0.5.RELEASE</version>
                    </dependency>
                    <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-websocket</artifactId>
                        <version>5.0.5.RELEASE</version>
                    </dependency>
                    <dependency>
                        <groupId>javax.websocket</groupId>
                        <artifactId>javax.websocket-api</artifactId>
                        <version>1.1</version>
                    </dependency>
                    <dependency>
                        <groupId>org.eclipse.jetty.aggregate</groupId>
                        <artifactId>jetty-all</artifactId>
                        <type>pom</type>
                        <version>9.3.3.v20150827</version>
                    </dependency>
                    <dependency>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-simple</artifactId>
                        <version>1.6.6</version>
                    </dependency>
                    <dependency>
                        <groupId>com.fasterxml.jackson.core</groupId>
                        <artifactId>jackson-databind</artifactId>
                        <version>2.5.0</version>
                    </dependency>
                    </dependencies>
```

有关更多信息，请参阅 Spring Framework 文档中的 [STOMP 支持](https://docs.spring.io/spring-integration/docs/5.0.5.RELEASE/reference/html/stomp.html)。

------

## Amazon MQExample .java
<a name="working-java-example"></a>

**重要**  
在以下示例代码中，生产者和使用者在单个线程中运行。对于生产系统（或测试代理实例故障转移），请确保您的创建者和使用者在单独的主机或线程上运行。

------
#### [ OpenWire ]

```
/*
 * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 */
                    
                    import org.apache.activemq.ActiveMQConnectionFactory;
                    import org.apache.activemq.jms.pool.PooledConnectionFactory;
                    
                    import javax.jms.*;
                    
                    public class AmazonMQExample {
                    
                    // Specify the connection parameters.
                    private final static String WIRE_LEVEL_ENDPOINT 
                            = "ssl://b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9-1.mq.us-east-2.amazonaws.com:61617";
                    private final static String ACTIVE_MQ_USERNAME = "MyUsername123";
                    private final static String ACTIVE_MQ_PASSWORD = "MyPassword456";
                    
                    public static void main(String[] args) throws JMSException {
                        final ActiveMQConnectionFactory connectionFactory =
                                createActiveMQConnectionFactory();
                        final PooledConnectionFactory pooledConnectionFactory =
                                createPooledConnectionFactory(connectionFactory);
                    
                        sendMessage(pooledConnectionFactory);
                        receiveMessage(connectionFactory);
                    
                        pooledConnectionFactory.stop();
                    }
                    
                    private static void
                    sendMessage(PooledConnectionFactory pooledConnectionFactory) throws JMSException {
                        // Establish a connection for the producer.
                        final Connection producerConnection = pooledConnectionFactory
                                .createConnection();
                        producerConnection.start();
                    
                        // Create a session.
                        final Session producerSession = producerConnection
                                .createSession(false, Session.AUTO_ACKNOWLEDGE);
                    
                        // Create a queue named "MyQueue".
                        final Destination producerDestination = producerSession
                                .createQueue("MyQueue");
                    
                        // Create a producer from the session to the queue.
                        final MessageProducer producer = producerSession
                                .createProducer(producerDestination);
                        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
                    
                        // Create a message.
                        final String text = "Hello from Amazon MQ!";
                        final TextMessage producerMessage = producerSession
                                .createTextMessage(text);
                    
                        // Send the message.
                        producer.send(producerMessage);
                        System.out.println("Message sent.");
                    
                        // Clean up the producer.
                        producer.close();
                        producerSession.close();
                        producerConnection.close();
                    }
                    
                    private static void
                    receiveMessage(ActiveMQConnectionFactory connectionFactory) throws JMSException {
                        // Establish a connection for the consumer.
                        // Note: Consumers should not use PooledConnectionFactory.
                        final Connection consumerConnection = connectionFactory.createConnection();
                        consumerConnection.start();
                    
                        // Create a session.
                        final Session consumerSession = consumerConnection
                                .createSession(false, Session.AUTO_ACKNOWLEDGE);
                    
                        // Create a queue named "MyQueue".
                        final Destination consumerDestination = consumerSession
                                .createQueue("MyQueue");
                    
                        // Create a message consumer from the session to the queue.
                        final MessageConsumer consumer = consumerSession
                                .createConsumer(consumerDestination);
                    
                        // Begin to wait for messages.
                        final Message consumerMessage = consumer.receive(1000);
                    
                        // Receive the message when it arrives.
                        final TextMessage consumerTextMessage = (TextMessage) consumerMessage;
                        System.out.println("Message received: " + consumerTextMessage.getText());
                    
                        // Clean up the consumer.
                        consumer.close();
                        consumerSession.close();
                        consumerConnection.close();
                    }
                    
                    private static PooledConnectionFactory
                    createPooledConnectionFactory(ActiveMQConnectionFactory connectionFactory) {
                        // Create a pooled connection factory.
                        final PooledConnectionFactory pooledConnectionFactory =
                                new PooledConnectionFactory();
                        pooledConnectionFactory.setConnectionFactory(connectionFactory);
                        pooledConnectionFactory.setMaxConnections(10);
                        return pooledConnectionFactory;
                    }
                    
                    private static ActiveMQConnectionFactory createActiveMQConnectionFactory() {
                        // Create a connection factory.
                        final ActiveMQConnectionFactory connectionFactory =
                                new ActiveMQConnectionFactory(WIRE_LEVEL_ENDPOINT);
                    
                        // Pass the sign-in credentials.
                        connectionFactory.setUserName(ACTIVE_MQ_USERNAME);
                        connectionFactory.setPassword(ACTIVE_MQ_PASSWORD);
                        return connectionFactory;
                    }
                    }
```

------
#### [ MQTT ]

```
/*
 * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 */
                    
                    import org.eclipse.paho.client.mqttv3.*;
                    
                    public class AmazonMQExampleMqtt implements MqttCallback {
                    
                    // Specify the connection parameters.
                    private final static String WIRE_LEVEL_ENDPOINT =
                            "ssl://b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9-1.mq.us-east-2.amazonaws.com:8883";
                    private final static String ACTIVE_MQ_USERNAME = "MyUsername123";
                    private final static String ACTIVE_MQ_PASSWORD = "MyPassword456";
                    
                    public static void main(String[] args) throws Exception {
                        new AmazonMQExampleMqtt().run();
                    }
                    
                    private void run() throws MqttException, InterruptedException {
                    
                        // Specify the topic name and the message text.
                        final String topic = "myTopic";
                        final String text = "Hello from Amazon MQ!";
                    
                        // Create the MQTT client and specify the connection options.
                        final String clientId = "abc123";
                        final MqttClient client = new MqttClient(WIRE_LEVEL_ENDPOINT, clientId);
                        final MqttConnectOptions connOpts = new MqttConnectOptions();
                    
                        // Pass the sign-in credentials.
                        connOpts.setUserName(ACTIVE_MQ_USERNAME);
                        connOpts.setPassword(ACTIVE_MQ_PASSWORD.toCharArray());
                    
                        // Create a session and subscribe to a topic filter.
                        client.connect(connOpts);
                        client.setCallback(this);
                        client.subscribe("+");
                    
                        // Create a message.
                        final MqttMessage message = new MqttMessage(text.getBytes());
                    
                        // Publish the message to a topic.
                        client.publish(topic, message);
                        System.out.println("Published message.");
                    
                        // Wait for the message to be received.
                        Thread.sleep(3000L);
                    
                        // Clean up the connection.
                        client.disconnect();
                    }
                    
                    @Override
                    public void connectionLost(Throwable cause) {
                        System.out.println("Lost connection.");
                    }
                    
                    @Override
                    public void messageArrived(String topic, MqttMessage message) throws MqttException {
                        System.out.println("Received message from topic " + topic + ": " + message);
                    }
                    
                    @Override
                    public void deliveryComplete(IMqttDeliveryToken token) {
                        System.out.println("Delivered message.");
                    }
                    }
```

------
#### [ STOMP\$1WSS ]

```
/*
 * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  https://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 */
                    
                    import org.springframework.messaging.converter.StringMessageConverter;
                    import org.springframework.messaging.simp.stomp.*;
                    import org.springframework.web.socket.WebSocketHttpHeaders;
                    import org.springframework.web.socket.client.WebSocketClient;
                    import org.springframework.web.socket.client.standard.StandardWebSocketClient;
                    import org.springframework.web.socket.messaging.WebSocketStompClient;
                    
                    import java.lang.reflect.Type;
                    
                    public class AmazonMQExampleStompWss {
                    
                    // Specify the connection parameters.
                    private final static String DESTINATION = "/queue";
                    private final static String WIRE_LEVEL_ENDPOINT =
                            "wss://b-1234a5b6-78cd-901e-2fgh-3i45j6k178l9-1.mq.us-east-2.amazonaws.com:61619";
                    private final static String ACTIVE_MQ_USERNAME = "MyUsername123";
                    private final static String ACTIVE_MQ_PASSWORD = "MyPassword456";
                    
                    public static void main(String[] args) throws Exception {
                        final AmazonMQExampleStompWss example = new AmazonMQExampleStompWss();
                    
                        final StompSession stompSession = example.connect();
                        System.out.println("Subscribed to a destination using session.");
                        example.subscribeToDestination(stompSession);
                    
                        System.out.println("Sent message to session.");
                        example.sendMessage(stompSession);
                        Thread.sleep(60000);
                    }
                    
                    private StompSession connect() throws Exception {
                        // Create a client.
                        final WebSocketClient client = new StandardWebSocketClient();
                        final WebSocketStompClient stompClient = new WebSocketStompClient(client);
                        stompClient.setMessageConverter(new StringMessageConverter());
                    
                        final WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
                    
                        // Create headers with authentication parameters.
                        final StompHeaders head = new StompHeaders();
                        head.add(StompHeaders.LOGIN, ACTIVE_MQ_USERNAME);
                        head.add(StompHeaders.PASSCODE, ACTIVE_MQ_PASSWORD);
                    
                        final StompSessionHandler sessionHandler = new MySessionHandler();
                    
                        // Create a connection.
                        return stompClient.connect(WIRE_LEVEL_ENDPOINT, headers, head,
                                sessionHandler).get();
                    }
                    
                    private void subscribeToDestination(final StompSession stompSession) {
                        stompSession.subscribe(DESTINATION, new MyFrameHandler());
                    }
                    
                    private void sendMessage(final StompSession stompSession) {
                        stompSession.send(DESTINATION, "Hello from Amazon MQ!".getBytes());
                    }
                    
                    private static class MySessionHandler extends StompSessionHandlerAdapter {
                        public void afterConnected(final StompSession stompSession,
                                                final StompHeaders stompHeaders) {
                            System.out.println("Connected to broker.");
                        }
                    }
                    
                    private static class MyFrameHandler implements StompFrameHandler {
                        public Type getPayloadType(final StompHeaders headers) {
                            return String.class;
                        }
                    
                        public void handleFrame(final StompHeaders stompHeaders,
                                                final Object message) {
                            System.out.print("Received message from topic: " + message);
                        }
                    }
                    }
```

------