一 . RabbitMq 交换机Exchange的Topic模式介绍:
Topic Exchange 转发信息主要是依据通配符 , 队列和交换机的绑定主要是依据一种模式(通配符+字符串),而当发送消息的时候,只有指定的Key和该模式相匹配的时候,消息才会被发送到该消息队列中.
Topic交换器介绍(转)
Topic Exchange 转发消息主要是根据通配符。 在这种交换机下,队列和交换机的绑定会定义一种路由模式,那么,通配符就要在这种路由模式和路由键之间匹配后交换机才能转发消息。
在这种交换机模式下:
路由键 必须是一串字符,用句号(.) 隔开,比如说 agreements.us,或者 agreements.eu.stockholm 等。
路由模式 必须包含一个 星号(*),主要用于匹配路由键指定位置的一个单词,比如说,一个路由模式是这样子:agreements..b.*,那么就只能匹配路由键是这样子的:第一个单词是 agreements,第四个单词是 b。 井号(#)就表示相当于一个或者多个单词,例如一个匹配模式是agreements.eu.berlin.#,那么,以agreements.eu.berlin开头的路由键都是可以的。
具体代码发送的时候还是一样,第一个参数表示交换机,第二个参数表示routing key,第三个参数即消息。如下:如上图所示:此类交换器使得来自不同的源头的消息可以到达一个队列,其实说的更明白一点就是模糊匹配的意思,例如:上图中红色对列的routingkey 为usa.#,#代表匹配任意字符,但是要想消息能到达此队列,usa.必须匹配后面的#号可以随意。图中usa.news,usa.weather都能找到红色队列,符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。因此“usa.#”能够匹配到“usa.news.XXX”,但是“usa.*” 只会匹配到“usa.XXX”。
注:交换器说到底是一个名称与队列绑定的列表。当消息发布到交换器时,实际上是由你所连接的信道,将消息路由键同交换器上绑定的列表进行比较,最后路由消息;
二 . 上代码(可以不需要建立两个module,一个springboot中直接发送接收消息,见下篇)
1. 新建maven工程,下面分别建两个module;rabbitmq_topic_receiver 和 rabbitmq_topic_sender;
父pom:
4.0.0
com.titter.rabbitmq
rabbitma_maven_topic_0409
1.0-SNAPSHOT
pom
rabbitmq_topic_receiver
rabbitmq_topic_sender
org.springframework.boot
spring-boot-starter-parent
2.0.1.RELEASE
UTF-8
UTF-8
1.8
Edgware.SR1
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
receiver pom :
4.0.0
com.titter.rabbitmq
rabbitmq_topic_receiver
0.0.1-SNAPSHOT
jar
rabbitmq_topic_receiver
Demo project for Spring Boot
com.titter.rabbitmq
rabbitma_maven_topic_0409
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-amqp
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
rabbitmq_topic_receiver
2. rabbitmq_maven_sender :
a. yml 中编辑rabbitMq的相关配置信息
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
application:
name: rabbit_topic_sender
b. 配置消息队列
-- 1. 配置队列Queue
-- 2. 配置交换机Exchange
-- 3. 将队列按照相应的规则绑定到交换机上
package com.titter.rabbitmq;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 1. yml文件编辑rabbitmq的相关配置信息
* 2. 配置消息队列 Queue
* a. 配置队列queue
* b. 配置交换机Exchange
* c. 将队列按照相应的规则绑定到交换机上
* 3. 发送消息 Sender *(使用AmqpTemplate)
* 4. 编写测试类
* Created by Administrator on 2018/4/9.
*/
@Configuration
public class TopicSenderConfig {
// a. 配置队列queue
@Bean(name = "message")
public Queue queueMessage(){
return new Queue("topic.message");
}
@Bean(name = "messages")
public Queue queueMessages(){
return new Queue("topic.messages");
}
// b. 配置交换机Exchange
@Bean
public TopicExchange exchange(){
return new TopicExchange("exchange");
}
// c. 将队列按照相应的规则绑定到交换机上
@Bean
public Binding bindingExchangeMessage(@Qualifier("message")Queue queueMessage,TopicExchange exchange){
return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
}
@Bean
public Binding bindingExchangeMessages(@Qualifier("messages")Queue queueMessages,TopicExchange exchange){
return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
}
}
c. 发送消息类编写 Sender**(使用AmqpTemplate)
package com.titter.rabbitmq;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Created by Administrator on 2018/4/9.
*/
@Component
public class TopicSender {
@Autowired
private AmqpTemplate template;
/*
参数分别表示 : 交换机exchange名称 ,发送的key, 发送的内容
*/
public void Sender(){
template.convertAndSend("exchange","topic.message","hello , i am rabbitmq ! ! ! ");
}
}
d. 编写测试类
package com.titter.rabbitmq;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = RabbitmqTopicSenderApplication.class)
public class RabbitmqTopicSenderApplicationTests {
@Autowired
private TopicSender topicSender;
@Test
public void contextLoads() {
topicSender.Sender();
}
}
3. rabbitmq_maven_receiver:
a. yml 中编辑rabbitMq的相关配置信息(因为8080端口被占用)
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
application:
name: rabbit_topic_receiver
server:
port: 8888
b. 配置消息队列
-- 1. 配置队列Queue
-- 2. 配置交换机Exchange
-- 3. 将队列按照相应的规则绑定到交换机上
package com.titter.rabbitmq;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 1. yml文件编辑rabbitmq的相关配置信息
* 2. 配置消息队列 Queue
* a. 配置队列queue
* b. 配置交换机Exchange
* c. 将队列按照相应的规则绑定到交换机上
* 3. 发送消息 Sender *(使用AmqpTemplate)
* 4. 编写测试类
* Created by Administrator on 2018/4/9.
*/
@Configuration
public class TopicSenderConfig {
// a. 配置队列queue
@Bean(name = "message")
public Queue queueMessage(){
return new Queue("topic.message");
}
@Bean(name = "messages")
public Queue queueMessages(){
return new Queue("topic.messages");
}
// b. 配置交换机Exchange
@Bean
public TopicExchange exchange(){
return new TopicExchange("exchange");
}
// c. 将队列按照相应的规则绑定到交换机上
@Bean
public Binding bindingExchangeMessage(@Qualifier("message")Queue queueMessage,TopicExchange exchange){
return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
}
@Bean
public Binding bindingExchangeMessages(@Qualifier("messages")Queue queueMessages,TopicExchange exchange){
return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
}
}
c. 接收消息类编写
package com.titter.rabbitmq;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* Created by Administrator on 2018/4/9.
*/
@Component
public class TopicReceiver {
@RabbitListener(queues = "topic.message") // 监听器监听指定的queue
public void process1(String str){
System.out.println("我是监听topic.message的 : "+str);
}
@RabbitListener(queues="topic.messages") // 监听器监听指定的queue
public void process2(String str){
System.out.println("我是监听topic.messages的 : "+str);
}
}
4. 测试
a . 先启动接收端的应用;
b . 启动发送端的测试类;
c. 发送端发送的消息时,(参数分别表示 : 交换机名称 exchange,发送的key, 发送的内容)
template.convertAndSend("exchange","topic.message","hello , i am rabbitmq ! ! ! ");
当发送端发送的key是 “topic.message”时,rabbitMq会根据第二个参数key去寻找有没有匹配此规则的队列,如果有,则把消息给他;如果匹配的不止一个,则把消息给匹配的每一个队列;显然此时参数2的key是匹配两个队列的,测试结果如下:
当将发送的key改成如下时,规则1 就不满足了;
template.convertAndSend("exchange","topic.messages","hello , i am rabbitmq ! ! ! ");
测试结果如下: