1.rabbitmq的工作模式主要分五种:
简单模式,工作模式,路由模式,主题模式,发布订阅模式
2.rabbitmq的主要交换机有五种(但是在开发中,主要掌握前三种就可以满足大部分业务):
直接交换机(Direct),主题交换机(Topic),扇形交换机(Fanout),首部交换机 (Headers),默认交换机(Default)
代码演示就先从交换机开始说起
------------------------------------------------------------------------------------------------------------------------------
1.直接交换机:
我们先创建一个配置类,在配置类中创建我们的直接交换机和队列,以及直接交换机跟队列的绑定关系,直接交换机有三种情景,如:一个交换机绑定一个队列然后一个消费者,一个交换机绑定一个队列有两个消费者,一个交换机绑定两个队列
-
一个交换机绑定一个队列然后一个消费者:
配置类:
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class config {
@Bean
public DirectExchange getDirectExchange()
{
// 创建一个直连交换机,并赋予名称:ljl-DirectExchange
return new DirectExchange("ljl-DirectExchange");
}
@Bean
public Queue directQueue(){
// 创建一个队列,并赋予名称:ljl-direct-Queue
return new Queue("ljl-direct-Queue");
}
// 直连交换机与队列的绑定关系
@Bean
public Binding directBinding() {
return BindingBuilder.bind(directQueue())
.to(getDirectExchange())
.with("direct_routing_key");
}
}
生产者:
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.UUID;
@RestController
// 生产者
public class testA {
@Autowired
private RabbitTemplate RabbitTemplate;
@GetMapping(value = "/DirectExchangeSendMessage")
public String sendMessage()
{
String id = UUID.randomUUID().toString();
String message = "开始发送消息";
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date());
HashMap<String, String> messageMap = new HashMap<>();
messageMap.put("id",id);
messageMap.put("message",message);
messageMap.put("time",time);
// 发送信息到名为ljl-DirectExchange的交换机上,并且让交换机把信息转发到名为direct_routing_key绑定关系队列中去
RabbitTemplate.convertAndSend("ljl-DirectExchange","direct_routing_key", messageMap);
return "发送成功";
}
}
消费者:
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
// mq侦听器(监听队列的名称)
@RabbitListener(queues = "ljl-direct-Queue")
public class client_A {
// mq处理器
@RabbitHandler
public void process(Map<String,String> message)
{
System.out.println("ljl-direct-Queue接收过来的消息:" + message);
}
}
以上代码以写好,我们直接来运行看下效果,运行项目,输入http://localhost:8080/DirectExchangeSendMessage,然后可以看到效果
- 一个交换机绑定一个队列然后两个消费者:
以上代码不变,直接写多一个消费者,然后来监听同一队列,看下效果:
可以看到,加多一个消费者监听同一个队列,消息是轮询分发的,一个消费者每次消费一条消息
- 一个交换机绑定两个队列然后两个消费者
配置类:
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class config {
@Bean
public DirectExchange getDirectExchange()
{
// 创建一个直连交换机,并赋予名称:ljl-DirectExchange
return new DirectExchange("ljl-DirectExchange");
}
@Bean
public Queue directQueue(){
// 创建一个队列,并赋予名称:ljl-direct-Queue
return new Queue("ljl-direct-Queue");
}
@Bean
public Queue directQueue2(){
// 创建一个队列,并赋予名称:ljl-direct-Queue2
return new Queue("ljl-direct-Queue2");
}
// 直连交换机与队列的绑定关系
@Bean
public Binding directBinding() {
return BindingBuilder.bind(directQueue())
.to(getDirectExchange())
.with("direct_routing_key");
}
// 直连交换机与队列的绑定关系2
@Bean
public Binding directBinding2() {
return BindingBuilder.bind(directQueue2())
.to(getDirectExchange())
.with("direct_routing_key2");
}
}
生产者:
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.UUID;
@RestController
// 生产者
public class testA {
@Autowired
private RabbitTemplate RabbitTemplate;
@GetMapping(value = "/DirectExchangeSendMessage")
public String sendMessage()
{
String id = UUID.randomUUID().toString();
String message = "开始发送消息";
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:sss").format(new Date());
HashMap<String, String> messageMap = new HashMap<>();
messageMap.put("id",id);
messageMap.put("message",message);
messageMap.put("time",time);
// 发送信息到名为ljl-DirectExchange的交换机上,并且让交换机把信息转发到名为direct_routing_key绑定关系队列中去
RabbitTemplate.convertAndSend("ljl-DirectExchange","direct_routing_key", messageMap);
HashMap<String, String> stringStringHashMap = new HashMap<>();
stringStringHashMap.put("message","嘿嘿");
RabbitTemplate.convertAndSend("ljl-DirectExchange","direct_routing_key2",stringStringHashMap);
return "发送成功";
}
}
消费者:
把client_A类的@RabbitListener(queues = "ljl-direct-Queue1")跟client_B类中的@RabbitListener(queues = "ljl-direct-Queue2")改好之后,直接运行看效果
两个消费者都收到了消息,以上就是直接交换机的基本使用
-----------------------------------------------------------------------------------------------------------------------------
2.主题交换机
跟路由交换机差不多,只不过是模糊匹配的模式
*:星号表示任意一个字符
#:表示任意一个或者多个字符
配置类:
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class configTopic {
public static final String topicA = "nihao.a";
public static final String topicB = "nihao.#";
@Bean
public TopicExchange getTopicExchange()
{
// 创建一个主题交换机
return new TopicExchange("ljl-TopicExchange");
}
@Bean
public Queue getQueueA()
{
return new Queue("ljl-Queue-A");
}
@Bean
public Queue getQueueB()
{
return new Queue("ljl-Queue-B");
}
@Bean
public Binding TopicBindingA()
{
// 绑定关系,而且绑定的键值为nihao.a,这样只要是消息携带的路由键是nihao.a,才会分发到该队列
return BindingBuilder.bind(getQueueA()).to(getTopicExchange()).with(topicA);
}
@Bean
public Binding TopicBindingB()
{
// 绑定关系,而且绑定的键值为nihao.#,这样只要是消息携带的路由键是包含了:"nihao.",都会才会分发到该队列
return BindingBuilder.bind(getQueueB()).to(getTopicExchange()).with(topicB);
}
}
生产者:
@RestController
public class testTopicA {
@Autowired
private RabbitTemplate rabbitTemplate;
@GetMapping(value = "/sendTopic")
public String sendTopic()
{
HashMap<String, String> messagMap_A = new HashMap<>();
messagMap_A.put("id_A", UUID.randomUUID().toString());
messagMap_A.put("message_A","主题交换机_A");
HashMap<String, String> messagMap_B = new HashMap<>();
messagMap_B.put("id_B", UUID.randomUUID().toString());
messagMap_B.put("message_B","主题交换机_B");
// nihao.a 绑定了ljl-Queue-A
// nihao.# 绑定了ljl-Queue-B
// 这个推送给A和B
rabbitTemplate.convertAndSend("ljl-TopicExchange","nihao.a",messagMap_A);
// 这个会推送给A
rabbitTemplate.convertAndSend("ljl-TopicExchange","nihao.adfadfa",messagMap_B);
return "成功";
}
}
消费者A:
@Component
@RabbitListener(queues = "ljl-Queue-A")
public class clientTopic_A {
@RabbitHandler
public void A(Map<String,String> map)
{
System.out.println("推送A的消息:" + map);
}
}
消费者B:
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
@RabbitListener(queues = "ljl-Queue-B")
public class clientTopic_B {
@RabbitHandler
public void B(Map<String,String> map)
{
System.out.println("推送B的消息:" + map);
}
}
运行代码,看结果:
可以看到,监听A队列的接收到一条消息,接收B队列的收到两条消息
------------------------------------------------------------------------------------------------------------------------------
3.扇形交换机:
把消息发送到交换机,然后交换机把消息推送到绑定该交换机的所有队列
配置类:
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class confgiFanout {
@Bean
public FanoutExchange getFanoutExchange()
{
// 定义扇形交换机
return new FanoutExchange("ljl-FanoutExchange");
}
@Bean
public Queue getQueueFanoutA()
{
return new Queue("ljl-getFanoutQueueA");
}
@Bean
public Queue getQueueFanoutB()
{
return new Queue("ljl-getFanoutQueueB");
}
@Bean
public Binding FanoutQueueA()
{
// 因为是扇形交换机,所以不用配置键
return BindingBuilder.bind(getQueueFanoutA()).to(getFanoutExchange());
}
@Bean
public Binding FanoutQueueB()
{
// 因为是扇形交换机,所以不用配置绑定键
return BindingBuilder.bind(getQueueFanoutB()).to(getFanoutExchange());
}
}
生产者:
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.UUID;
@RestController
public class testFanout {
@Autowired
private RabbitTemplate rabbitTemplate;
@GetMapping(value = "/sendFanout")
public String sendTopic()
{
HashMap<String, String> messagMap_A = new HashMap<>();
messagMap_A.put("id_A", UUID.randomUUID().toString());
messagMap_A.put("message_A","扇形交换机");
// 这里不用写绑定键,因为是扇形交换机
rabbitTemplate.convertAndSend("ljl-FanoutExchange","",messagMap_A);
return "成功";
}
}
消费者:
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class clientFanout {
@RabbitListener(queues = "ljl-getFanoutQueueA")
@RabbitHandler
public void FanoutA(Map<String, String> message)
{
System.out.println("队列A接收过来的推送消息:" + message);
}
@RabbitListener(queues = "ljl-getFanoutQueueB")
@RabbitHandler
public void FanoutB(Map<String, String> message)
{
System.out.println("队列B接收过来的推送消息:" + message);
}
}
运行代码看结果:
可以看到,队列A跟队列B都收到了消息
------------------------------------------------------------------------------------------------------------------------------
首部交换机跟默认交换机在这里就不赘述了,因为在开发中比较少用到,掌握三个交换机的写法就可以满足大部分的开发要求了
简单模式:简单模式是使用默认的交换机
工作模式:工作模式也是使用简单的交换机,然后信息轮询分发
主题模式:使用的是主题交换机
路由模式:使用的是直接交换机
发布订阅模式:使用的是扇形交换机