前几篇已经说了mq的基本用法,也分别使用了普通的java写法和spring boot基于注解的方法去实现了mq的接收消息。我们上一节的最后给大家说过,有一个叫routingKey的东西,好像我们暂时还没有使用过。本节讲的这两种模式都会使用到routingKey来实现我们的mq消费。
听这个名称就知道这个模式和路由有关,我们上一篇说的广播的模式这种方式有点缺少灵活性,他只是广播给所有人,假如我们有个场景是这样的:我们总共有10个消费者,而生产者前几条消息发送给前5个,后几条消息发送给之后的人,这时候如果使用广播模式发现无法达到我们的效果。这时候就发现广播这种模式不灵活,没法根据我们的想法传送消息。我们用direct路由器来替换它。direct路由器背后的路由算法很简单:只有当消息的路由键routing key与队列的绑定键binding key完全匹配时,该消息才会进入该队列。
我们从这个图可以看到我们的交换机和每一个队列中间都有个连线,这个连线都有一个值,其实这个值就是routingKey,而这个连线就相当于绑定,通过routingKey将交换机与队列进行绑定,这样的话,我们可以设置什么样的数据发给c1,什么样的数据发送给c2,只要设置相应的routingKey就能到达我们的要求,这种方式是不是很灵活。
其实代码实现也是很简单的
private static String EXCHANGE_NAME="direct_name";
@Autowired
RabbitTemplate amqpt;
@RequestMapping(value="test")
public void test() throws InterruptedException{
amqpt.convertAndSend(EXCHANGE_NAME,"direct", "hello word");
// amqpt.convertAndSend
System.err.println("消息发送成功");
}
@RequestMapping(value="test1")
public void test1() throws InterruptedException{
amqpt.convertAndSend(EXCHANGE_NAME,"direct1", "您好!");
System.err.println("消息发送成功");
}
我们看convertAndSend的参数,第一个是交换机的名称,第二个是routingKey,第三个是消息。到这里我们的生产者就已经完成了。我们看一下他们是如何绑定的
private static String EXCHANGE_NAME="direct_name";
@Bean
public Queue queue(){
return new Queue("direct_queue");
}
@Bean
public Queue queue1(){
return new Queue("direct_queue1");
}
@Bean
public DirectExchange directExchange(){
return new DirectExchange(EXCHANGE_NAME);
}
@Bean
public Binding binddirect(Queue queue,DirectExchange directExchange){
return BindingBuilder.bind(queue).to(directExchange).with("direct");
}
@Bean
public Binding binddirect1(Queue queue1,DirectExchange directExchange){
return BindingBuilder.bind(queue1).to(directExchange).with("direct");
}
@Bean
public Binding binddirect2(Queue queue1,DirectExchange directExchange){
return BindingBuilder.bind(queue1).to(directExchange).with("direct1");
}
其实也很简单,因为我们路由模式下的交换机类型是direct,所以我们声明一个direct的交换机的,然后我们通过BindingBuilder.bind(queue).to(directExchange).with(“direct”)将交换机和队列通过routingKey绑定在一起,我们发现这个代码里面queue1通过direct1绑定到交换机,queue、queue1通过direct绑定到交换机。也就是我们发消息,只要通过这个交换机发送的消息含有routingKey为direct1就会发给queue1队列,含有routingKey为direct就会发给queue1队列和queue队列。
而消费者也什么都可以不用管,只需要监听相应的队列即可。
这种方式最大的特点就是灵活。
topic模式也称为主题模式,其实他相对于routing模式最大的好处就是他多了一种匹配模式的路由,怎么理解匹配呢,其实就相当于我们之前正则的.*这种,不过他的匹配机制可能不是这种,而他的工作流程图如下
我们先讲一下他的匹配规则吧,其实除了匹配规则外,他的作用就和routing模式一样
绑定键binding key也必须是这种形式。以特定路由键发送的消息将会发送到所有绑定键与之匹配的队列中。但绑定键有两种特殊的情况:
①*(星号)仅代表一个单词
②#(井号)代表任意个单词
我们就拿上面的图解释,.orange.能匹配 a.orange.a,b.orange.a,aa.orange.bb等等
lay.#能匹配的就多了,他只要一lay.开头的都匹配,他可以匹配lay.a,lay.a.b,lay.b.c等。
这样是不是很方便,比如我们想将log的发给q1队列,其他的发给q2,那么我们只需要定义log.#、或者log.*,那么你发送给q1队列的数据就是log日志的消息。
所以这种方式对于处理一个分类的消息特别方便。
而他的实现也不是很难
//声明一个交换机的名称
private static String EXCHANGE_NAME="exchange_topic";
@Autowired
AmqpTemplate amqpt;
@RequestMapping(value="test")
public void test() throws InterruptedException{
//第一个参数是交换机,第二个参数是routingKey,第三个参数是要发送的消息,支持实体对象
amqpt.convertAndSend(EXCHANGE_NAME,"topic.name.c", "hello word");
// amqpt.convertAndSend
System.err.println("消息发送成功");
}
@RequestMapping(value="test1")
public void test1() throws InterruptedException{
amqpt.convertAndSend(EXCHANGE_NAME,"topic.a", "您好!");
System.err.println("消息发送成功");
}
而我们绑定的地方配置类如下
//这个交换机的名称要和我们发送消息的交换机名称一致
private static String EXCHANGE_NAME="exchange_topic";
//新建一个队列,名称为exchange_queue
@Bean
public Queue queue(){
return new Queue("exchange_queue");
}
//新建一个队列,名称为exchange_queue1
@Bean
public Queue queue1(){
return new Queue("exchange_queue1");
}
/**
* 声明一个topic的交换机,不同类型的可以声明成不同的,比如fanout、direct等
* @return
*/
@Bean
public TopicExchange topicExchange(){
return new TopicExchange(EXCHANGE_NAME);
}
/**
* 队列与交换机的绑定,通过routingKey来绑定,fanout模式是不需要routingKey的,因为他是直接绑定队列的
* @param queue
* @param topicExchange
* @return
*/
@Bean
public Binding binddirect(Queue queue,TopicExchange topicExchange){
return BindingBuilder.bind(queue).to(topicExchange).with("topic.#");
}
@Bean
public Binding binddirect1(Queue queue1,TopicExchange topicExchange){
return BindingBuilder.bind(queue1).to(topicExchange).with("topic.*");
}
我们会发现queue1 和queue2 绑定的是通过这种#和*的方式绑定,然后写完消费者,启动分别访问test和test1的接口,你就会发现test接口会触发queue的队列,而test1接口会触发queue1和queue的消息,这个和我们讲的效果一样。大家可以自己动手实现以下