跳到主要内容
版本:4.1.1

AMQP 抽象

Doubao 中英对照 AMQP Abstractions

Spring AMQP 由两个模块组成(分发包中各对应一个 JAR):spring-amqp 和 spring-rabbit。'spring-amqp' 模块包含 org.springframework.amqp.core 包。在该包中,你可以找到代表核心 AMQP“模型”的类。我们的意图是提供不依赖任何特定 AMQP broker 实现或客户端库的通用抽象。最终用户代码可以更方便地跨厂商实现移植,因为它只针对抽象层开发。这些抽象随后由特定于 broker 的模块(例如 'spring-rabbit')实现。目前只有一个 RabbitMQ 实现。不过,除 RabbitMQ 之外,这些抽象还在 .NET 中使用 Apache Qpid 得到了验证。由于 AMQP 工作在协议层,原则上你可以将 RabbitMQ 客户端用于任何支持相同协议版本的 broker,但我们目前不测试其他 broker。

本概述假定你已经熟悉 AMQP 规范的基础知识。如果不熟悉,请参阅其他资源中列出的资源。

Message​

0-9-1 AMQP 规范并未定义 Message 类或接口。相反,在执行诸如 basicPublish() 之类的操作时,内容以字节数组参数传递,额外属性则作为单独的参数传入。Spring AMQP 定义了一个 Message 类,作为更通用的 AMQP 领域模型表示的一部分。Message 类的目的是将消息体和属性封装在单个实例中,从而使 API 更加简洁。下例展示了 Message 类的定义:

public class Message {

private final MessageProperties messageProperties;

private final byte[] body;

public Message(byte[] body, MessageProperties messageProperties) {
this.body = body;
this.messageProperties = messageProperties;
}

public byte[] getBody() {
return this.body;
}

public MessageProperties getMessageProperties() {
return this.messageProperties;
}
}

MessageProperties 接口定义了若干常用属性,例如 'messageId'、'timestamp'、'contentType' 等。你还可以通过调用 setHeader(String key, Object value) 方法,用用户自定义的 'headers' 扩展这些属性。

important

从 1.5.7、1.6.11、1.7.4 和 2.0.0 版本开始,如果消息体是一个序列化的 Serializable Java 对象,在执行 toString() 操作时(例如在日志消息中),(默认)不再对其进行反序列化。这是为了防止不安全的反序列化。默认情况下,只有 java.util 和 java.lang 类会被反序列化。要恢复以前的行为,你可以通过调用 Message.addAllowedListPatterns(…​) 添加允许的类/包模式。支持简单的 * 通配符,例如 com.something.*, *.MyClass。无法反序列化的消息体在日志消息中以 byte[<size>] 表示。

Exchange​

Exchange 接口代表一个 AMQP 交换机,即消息生产者发送到的目标。broker 虚拟主机中的每个交换机都有唯一名称以及其他一些属性。下例展示了 Exchange 接口:

public interface Exchange extends Declarable {

String getName();

String getType();

boolean isDurable();

boolean isAutoDelete();

Map<String, Object> getArguments();

}

如你所见,Exchange 还有一个由 ExchangeTypes 中定义的常量表示的 'type'。基本类型有:direct、topic、fanout 和 headers。在核心包中,你可以找到每种类型对应的 Exchange 接口实现。这些 Exchange 类型在处理队列绑定的方式上各不相同。例如,Direct 交换机允许队列以固定路由键(通常是队列名)绑定。Topic 交换机支持使用路由模式进行绑定,路由模式可包含 '*' 和 '#' 通配符,分别表示“恰好一个”和“零个或多个”。Fanout 交换机向所有绑定到它的队列发布消息,而不考虑任何路由键。关于这些及其他交换机类型的更多信息,请参见 AMQP Exchanges。

从 3.2 版本开始,引入了 ConsistentHashExchange 类型,以便在应用配置阶段使用。它为交换机类型提供了 x-consistent-hash 等选项。允许配置 hash-header 或 hash-property 交换机定义参数。相应的 RabbitMQ rabbitmq_consistent_hash_exchange 插件必须在 broker 上启用。关于一致性哈希交换机的用途、逻辑和行为的更多信息,参见 RabbitMQ 官方文档。

备注

AMQP 规范还要求任何 broker 都提供一个没有名称的“默认” direct 交换机。所有已声明的队列都会以其名称作为路由键绑定到该默认 Exchange。你可以在 AmqpTemplate 中了解更多关于 Spring AMQP 中默认交换机用法的内容。

Queue​

Queue 类代表消息消费者从中接收消息的组件。与各种 Exchange 类一样,我们的实现旨在作为这种核心 AMQP 类型的抽象表示。下面的清单展示了 Queue 类:

public class Queue  {

private final String name;

private final boolean durable;

private final boolean exclusive;

private final boolean autoDelete;

/**
* The queue is durable, non-exclusive and non auto-delete.
*
* @param name the name of the queue.
*/
public Queue(String name) {
this(name, true, false, false);
}

// Getters and Setters omitted for brevity

}

注意构造函数接收队列名。根据实现的不同,admin 模板可能提供生成唯一命名队列的方法。此类队列可用作“reply-to”地址,或用于其他临时场景。因此,自动生成队列的 'exclusive' 和 'autoDelete' 属性都会被设置为 'true'。

备注

关于使用命名空间支持声明队列(包括队列参数)的信息,请参见配置 Broker中关于队列的章节。

Binding​

鉴于生产者发送到交换机、消费者从队列接收消息,将队列连接到交换机的绑定对于通过消息传递连接这些生产者和消费者至关重要。在 Spring AMQP 中,我们定义了一个 Binding 类来表示这些连接。本节回顾将队列绑定到交换机的基本选项。

我们提供了一个 BindingBuilder 来支持“流式 API”风格,如下例所示:

Queue queue = ...;
// bind a queue to a DirectExchange with a fixed routing key
Binding directBinding = BindingBuilder.bind(queue).to(new DirectExchange("someDirectExchange")).with("foo.bar");
// bind a queue to a TopicExchange with a routing pattern
Binding topicBinding = BindingBuilder.bind(queue).to(new TopicExchange("someTopicExchange")).with("foo.*");
// bind a queue to a FanoutExchange with no routing key
Binding fanoutBinding = BindingBuilder.bind(queue).to(new FanoutExchange("someFanoutExchange"));
备注

为清晰起见,上例展示了 BindingBuilder 类,但这种风格在静态导入 'bind()' 方法时也同样适用。

Binding 类的实例本身只保存关于一条连接的数据。换句话说,它不是一个“活跃”组件。不过,正如你将在后面的配置 Broker中看到的,AmqpAdmin 类可以使用 Binding 实例在 broker 上实际触发绑定操作。另外,正如在同一节中所见,你可以在 @Configuration 类中使用 Spring 的 @Bean 注解来定义 Binding 实例。还有一个便捷的基类,进一步简化了生成 AMQP 相关 bean 定义的方式,并能识别队列、交换机和绑定,使它们在应用程序启动时全部在 AMQP broker 上声明。

AmqpTemplate 也定义在核心包中。作为实际 AMQP 消息传递所涉及的主要组件之一,它在自己的章节中详细讨论(参见 AmqpTemplate)。