|
此版本仍在开发中,目前尚不稳定。如需最新稳定版本,请使用 Spring AMQP 4.0.2! |
AMQP 抽象
Spring AMQP 包含两个模块(每个模块在分发包中由一个 JAR 文件表示):spring-amqp 和 spring-rabbit。'spring-amqp' 模块包含 org.springframework.amqp.core 包。在该包中,您可以找到代表核心 AMQP “模型”的类。我们的目标是提供通用抽象,这些抽象不依赖于任何特定的 AMQP 代理实现或客户端库。终端用户代码可更易于跨提供商实现进行移植,因为它只需针对抽象层进行开发即可。这些抽象随后由面向具体代理的模块实现,例如 'spring-rabbit'。目前仅提供 RabbitMQ 实现。然而,这些抽象已在 .NET 中通过 Apache Qpid 和 RabbitMQ 进行了验证。由于 AMQP 在协议层面运行,原则上您可使用 RabbitMQ 客户端与任何支持相同协议版本的代理配合使用,但目前我们并未对其他代理进行测试。
本概述假设您已经熟悉 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' 扩展这些属性。
从版本 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 表示一个 AMQP 交换机(Exchange),这是消息生产者发送消息的目标。
每个代理(Broker)的虚拟主机内的每个交换机都具有唯一的名称以及若干其他属性。
以下示例展示了 Exchange 接口:
public interface Exchange {
String getName();
String getExchangeType();
boolean isDurable();
boolean isAutoDelete();
Map<String, Object> getArguments();
}
如您所见,Exchange 也具有由 ExchangeTypes 中定义的常量表示的 'type'(类型)。
基本类型包括:direct、topic、fanout 和 headers。
在核心包中,您可以找到针对这些类型中的每一种的 Exchange 接口实现。
这些 Exchange 类型在如何处理与队列的绑定方面表现出不同的行为。
例如,Direct 交换机允许队列通过固定路由键(通常为队列名称)进行绑定。
而 Topic 交换机则支持使用路由模式进行绑定,该模式可包含 '*' 和 '#' 通配符,分别代表“恰好一个”和“零个或多个”。Fanout 交换机会将消息发布到所有已绑定到它的队列,而无需考虑任何路由键。
有关这些以及其他交换机类型的更多信息,请参阅 AMQP 交换机。
从版本 3.2 开始,在应用程序配置阶段引入了 ConsistentHashExchange 类型,以方便配置。它提供了诸如 x-consistent-hash 这样的交换类型选项,可用于配置 hash-header 或 hash-property 交换定义参数。相应的 RabbitMQ rabbitmq_consistent_hash_exchange 插件必须在代理(broker)上启用。关于一致性哈希交换(Consistent Hash Exchange)的目的、逻辑与行为的更多详情,请参阅官方 RabbitMQ 文档。
AMQP 规范还要求任何代理必须提供一个名为“默认”的直连交换机(direct exchange),该交换机没有名称。所有声明的队列都会绑定到该默认 Exchange 交换机上,其绑定键(routing key)即为队列的名称。您可以在 AmqpTemplate 中了解 Spring AMQP 中默认交换机的使用方式。 |
队列
类 Queue 表示消息消费者从中接收消息的组件。与各种 Exchange 类似,我们的实现旨在作为此核心 AMQP 类型的抽象表示。以下列表显示了 Queue 类:
public class Queue {
private final String name;
private volatile boolean durable;
private volatile boolean exclusive;
private volatile boolean autoDelete;
private volatile Map<String, Object> arguments;
/**
* 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
}
请注意,构造函数接受队列名称。
根据具体实现,管理模板可能会提供用于生成唯一命名队列的方法。
此类队列在作为“回复地址”或在其他临时场景中非常有用。
因此,自动生成队列的‘exclusive’(独占)和‘autoDelete’(自动删除)属性都将被设置为‘true’。
| 请参阅《配置代理》(Configuring the Broker)一节中关于队列的部分,以了解如何使用命名空间支持声明队列,包括队列参数。 |
绑定
鉴于生产者向交换机发送消息,而消费者从队列接收消息,将队列与交换机连接起来的绑定(bindings)对于通过消息传递实现生产者与消费者之间的连接至关重要。在 Spring AMQP 中,我们定义了一个 Binding 类来表示这些连接。本节将回顾将队列绑定到交换机的基本选项。
您可以将队列绑定到一个 DirectExchange,并使用固定的路由键,如下例所示:
new Binding(someQueue, someDirectExchange, "foo.bar");
您可以将队列与一个 TopicExchange 绑定,使用路由模式,如下例所示:
new Binding(someQueue, someTopicExchange, "foo.*");
您可以将队列绑定到一个 FanoutExchange,而无需路由键,如下例所示:
new Binding(someQueue, someFanoutExchange);
我们还提供一个 BindingBuilder,以方便实现“流畅式 API”风格,如下例所示:
Binding b = BindingBuilder.bind(someQueue).to(someTopicExchange).with("foo.*");
为了清晰起见,前面的示例展示了 BindingBuilder 类,但这种风格在使用静态导入 'bind()' 方法时效果很好。 |
单独来看,Binding 类的一个实例仅保存连接的相关数据。换句话说,它并不是一个“活跃”的组件。然而,正如您将在配置代理一节中看到的那样,AmqpAdmin 类可以利用Binding 实例在代理上实际触发绑定操作。此外,如同一节所示,您还可以通过在@Configuration 类中使用 Spring 的@Bean 注解来定义Binding 实例。此外,还提供了一个便捷的基类,进一步简化了生成与 AMQP 相关 Bean 定义的方法,并能识别队列、交换机和绑定关系,以便在应用程序启动时将它们全部在 AMQP 代理上声明。
代码 AmqpTemplate 也定义在核心包中。作为实际 AMQP 消息传递中的主要组件之一,它在其独立章节中有详细讨论(参见 AmqpTemplate)。