Spring AMQP 中的核心概念

微笑、不失礼 提交于 2019-12-17 00:07:33

本文主要介绍Spring AMQP中的用于开发的核心概念

Spring AMQP 包含了两个核心的模块 spring-amqpspring-rabbit.

image-20191216141555472

spring-amqp 模块包含了 org.springframeworks.amqp.core 包,该包里面包含了了AMQP协议里面的核心概念。本意就是该包里面的内容是一个关于AMQP协议高度抽象的层级,并不会依赖于任何具体的AMQP中间件的实现。

Message 消息

0-9-1 AMQP协议中并没有的定义 Message 类或者接口,但是当我们在做一些基本的 操作的是时候,例如 basicPublish() 的时候,传输的内容是一个 字节数据和一些额外的分开的属性值。在 Spring AMQP 中,就定义了一个 Message 类来代表一个更通用的AMQP 域。Message 类的主要目的就在于封装 content 和 一些属性。(实际定义和如下会有一些区别)

@Data
@AllArgsConstructor
public class Message {

    private final MessageProperties messageProperties;

    private final byte[] body;

}

MessageProperties 中会定义一系诶公共的属性,比如,messageID, timestamp, contentType等等。也可以通过自定义的 headers 来实现来扩展这些属性。 例如,通过 setHeader(String key, Object value) 来自定义。

1.5.7, 1.6.11, 1.7.4, 和 2.0.0 版本开始,如果一个Message的 Body 是一个序列化的后的 Serializable 对象,那么调用toString() 方法的时候,默认不会再进行反序列操作。主要是为了预防不安全的反序列化操作。默认情况下,只有 java.utiljava.lang 两个包下的类会被反序列化。如果你想增加某些类的反序列化操作,你可以调用 ``Message.addWhiteListPatterns(…). 方法,增加全限定符合通配符来指定某些类。

Exchange 交换器

Exchange 接口代表了一个 AMQP Exchange,这就是消息的生产者将消息发送的目标地。每一个 Exchange 都有一个虚拟的 virtual host(具有独一无二的名字)

public interface Exchange {

    String getName();

    String getExchangeType();

    boolean isDurable();

    boolean isAutoDelete();

    Map<String, Object> getArguments();

}

Exchange 具有一个 type,该Type定义在了 ExchangeTypes 类中。基础的类型有 direct, topic, fanoutheaders

  • Direct:(默认)其类型的行为是“先匹配、再投送”,即在绑定时设定一个 routing_key,消息的 routing_key 匹配时,才会被交换器投送到绑定的队列中去。
  • Topic:按规则转发消息(最灵活)。支持‘*’ (1个)和 # (0个或者多个)等通配符。
  • Headers:设置 header attribute 参数类型的交换机。
  • Fanout:转发消息到所有绑定队列。

direct

RabbitMQ的默认模式,根据RouteKey全文匹配寻找队列。所以定义了Exchange 和 Queue 之后,还需要定义绑定关系(路由键)。

img

第一个 X - Q1 就有一个 binding key,名字为 orange;X - Q2 就有 2 个 binding key,名字为 black 和 green。当消息中的路由键和这个 binding key 对应上的时候,那么就知道了该消息去到哪一个队列中。

Topic Exchange

Topic Exchange 转发消息主要是根据通配符。在这种交换机下,队列和交换机的绑定会定义一种路由模式,那么,通配符就要在这种路由模式和路由键之间匹配后交换机才能转发消息。

  • 路由键必须是一串字符,用句号(.)隔开,比如 agreements.us,或者 agreements.eu.stockholm 等;
  • 路由模式必须包含一个 星号(* ),主要用于匹配路由键指定位置的一个单词,比如,一个路由模式是这样子,agreements…b.*,那么就只能匹配路由键是这样子的,第一个单词是 agreements,第3个单词是 b;井号(#)就表示相当于一个或者多个单词,例如一个匹配模式是 agreements.eu.berlin.#,那么,以 agreements.eu.berlin 开头的路由键都是可以的。

Topic 和 Direct 类似, 只是匹配上支持了“模式”,在“点分”的 routing_key 形式中, 可以使用两个通配符:

  • * 表示一个词
  • # 表示零个或多个词

Headers Exchange

Headers 也是根据规则匹配,相较于 Direct 和 Topic 固定地使用 routing_key,headers 则是一个自定义匹配规则的类型。

在队列与交换器绑定时,会设定一组键值对规则,消息中也包括一组键值对(headers 属性),当这些键值对有一对或全部匹配时,消息被投送到对应队列。

Fanout Exchange

Fanout Exchange 消息广播的模式,不管路由键或者是路由模式,会把消息发给绑定给它的全部队列,如果配置了 routing_key 会被忽略。

Queue 队列

队列类代表了消息消费者从中接受消息的组件。就如各种 Exchange 类一样,下面的代码也是为了高度的抽象核心的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

}

值得注意的是,构造函数中指定了Queue名字,但是实际上 admin template 方法中会自己生产独一无二的队列名字。自定义生成队列名字的方法可以在 reply-to 地址或者其他的 临时情况下使用。 对于这样的自动生成Queue的场景,其中的 exclusiveautoDelete 属性必须设定为true。

Binding 绑定

生产者将消息发送到 Exchange,消费者从 queue 中消费消息,那么 Binding决定 Exchange 如何到达 Queue。在 Spring AMQP 中,我们定义了一个 Binding 类来代表这种连接。下面将说明一些基本的选项来做这些来绑定 queue 和 Exchange。

  1. 通过固定的routing key 来绑定一个队列到 DirectExchange

    new Binding(someQueue, someDirectExchange, "foo.bar");
    
  2. 通过routing pattern 来绑定队列到TopicExchange.

    new Binding(someQueue, someTopicExchange, "foo.*");
    
  3. 不指定routring 来绑定队列到 fanoutExchange

  4. new Binding(someQueue, someFanoutExchange);
    
  5. 通过 BindingBuilder 采用流式API风格构造

    Binding b = BindingBuilder.bind(someQueue).to(someTopicExchange).with("foo.*");
    

就其本身而言,Binding对象仅保存和connection有关的数据。但是你可以在接下来的配置中间件的章节中看到,AmqpAdmin 类可以使用 Binding 实例来实际的 trigger 绑定关系(在中间件中)

参考文献


  1. Spring Boot RabbitMQ 详解
  2. Spring AMQP
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!