前言
在描述RabbitMQ之前我们需要先了解什么是消息队列,以及消息队列作用是什么.,其次还需要力了解AMQP和JMS协议;
1,什么是消息队列?
消息队列(Message Queue),简称MQ,他其实就是应用程序之间通信的方法;具体解释就是我们可以将消息发送到队列中,然后不同的应用程序(我的理解:可以是一个模块,微服务)根据需求来监听队列中的消息,根据消息判断并执行各自的功能;
消息队列的作用就显而易见了:就是应用程序之间通信;
2,实现消息队列的两种协议方式?
MQ是消息通信的模型;实现MQ的大致有两种主流方式:AMQP、JMS
3.什么是AMQP?
AMQP是一种协议,更加准确的说是它是一种"连接协议",这也是和JMS的本质区别,
AMQP不从API层进行限定,而是直接定义网络交换的数据格式。
4,什么是JMS?
JMS即Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
5.AMQP和JMS的区别?
1,JMS是定义了统一的接口,来对消息操作进行统一;AMQP是通过规定协议来统一数据交互的格式;
2,JMS限定了必须使用Java语言;AMQP只是协议,不规定实现方式,因此是跨语言的;
3,JMS规定了两种消息模式;而AMQP的消息模式更加丰富;
5,什么是RabbitMQ?
了解了上面几个概念,那么RabbitMQ的概念就简单了,他其实就是一种基于AMQP协议实现的消息队列;它是一种应用程序之间通信的方法,现在应用很广泛;
6,RabbitMQ的六种模式.
1,简单模式;
2,work模式;
3,发布与订阅模式;
4,Routing路由模式;
5,Topics主题模式;
RPC远程调用模式(不作重点记忆)
7,SpringBoot整合RabbitMQ(消息发送方)
1,导入先关启动器依赖;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2,在.yml文件中进行配置RabbitMQ
spring:
rabbitmq:
host: localhost
port: 5672
virtual-host: /mrkay
username: mrkay
password: lk0313
3,创建配置类,绑定交换机和队列;
(消息生产方不需要监听队列情况下我们可以只就创建交换机即可,因为消息发送方只需要将消息发送给队列)
@Configuration
public class RabbitMQConfig {
//交换机名字
public static final String MRKAY_EXECHANGE = "mrkay_exechange";
//队列名字
public static final String MRKAY_QUEUQ = "mrkay_queue";
//声明交换机
@Bean("mrkay_exechange")
public Exchange topicExechange() {
return ExchangeBuilder.topicExchange(MRKAY_EXECHANGE).durable(true).build();
}
//声明队列
@Bean("mrkay_queue")
public Queue queue() {
return QueueBuilder.durable(MRKAY_QUEUQ).build();
}
//交换价和队列进行绑定,并指定routingKey
@Bean
public Binding queueExechange(@Qualifier("mrkay_queue") Queue queue, @Qualifier("mrkay_exechange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("mrkay.#").noargs();
}
}
4,使用RabbitTemplate放消息到交换机(这里使用的路由模式是routing路由模式)
@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitMQTest {
@Autowired
private RabbitTemplate rabbitTemplate;
//向队列发送消息
@Test
public void send(){
rabbitTemplate.convertAndSend(RabbitMQConfig.MRKAY_EXECHANGE,"mrkay.show01","routingkey为mrkay.show01");
rabbitTemplate.convertAndSend(RabbitMQConfig.MRKAY_EXECHANGE,"mrkay.show02","routingkey为mrkay.show02");
rabbitTemplate.convertAndSend(RabbitMQConfig.MRKAY_EXECHANGE,"mrkay.show03","routingkey为mrkay.show03");
rabbitTemplate.convertAndSend(RabbitMQConfig.MRKAY_EXECHANGE,"mrkay.show04","routingkey为mrkay.show04");
rabbitTemplate.convertAndSend(RabbitMQConfig.MRKAY_EXECHANGE,"amrkay.show","routingkey为mrkay.ashow");
}
}
8,SpringBoot整合RabbitMQ(消息消费方)
以下三步与消息发送方整合步骤一样不多阐述
1,添加依赖;
2,.yml文件中进行配置;
3,编写配置类绑定交换机和队列;(如果消息生产方的MQ配置类中没有创建队列以及实现交换机和队列的绑定这里的配置类中就必须创建队列并与交换机绑定)
4,创建消息监听类监听指定队列;
@Component
public class MyListener {
/**
* 监听指定的消息队列
* 参数为监听到的消息:自动封装进去了
* 使用指定注解监听指定的队列
*/
@RabbitListener(queues = "mrkay_queue")
public void myListener(String message) {
System.out.println("消费方:"+message);
}
}
9,总结一下RabbitMQ的6种工作模式
1,simple简单模式
消息产生者将消息放入队列;消息的消费者(consumer) 监听(monitor) 消息队列,如果队列中有消息,就消费掉,消息被拿走后,自动从队列中删除;
2,work工作模式(资源的竞争):
消息产生者将消息放入队列消费者可以有多个,消费者1,消费者2,同时监听同一个队列,C1 C2共同争抢当前的消息队列内容,谁先拿到谁负责消费消息,高并发情况下可能存在的问题是,一个消息可能被多个消费者共同消费(可以设置一个开关(syncronize,与同步锁的性能不一样) 保证一条消息只能被一个消费者使用);
3,publish/subscribe发布订阅(共享资源):
消息产生者将消息放入交换机,交换机发布订阅把消息发送到所有消息队列中,对应消息队列的消费者拿到消息进行消费(一个生产者对应多个消费者:也就是一个交换机绑定多个队列,每一个队列各被一个消费者监听);
4,routing路由模式:
消息生产者向交换机X发送消息并指定一个RoutingKey(相当队列的门牌号),X将消息发送给RoutingKey完全匹配的队列,对应队列消费者拿到消息进行消费(一个生产者对应多个消费者,可以说是一个交换机有目的的绑定多个队列,每一个队列各被一个消费者监听);
5,topic 主题模式(路由模式的一种):
这个其实也是一种Routing路由模式,只不过我们在做交换机和队列的绑定时指定的RoutingKey使用的是通配符( * 和 # ),其中星号代表多个单词,井号代表一个单词,交换机在拿着routingKey(门牌号)发送消息给队列的时候会进行模糊匹配;交换机根据key的规则模糊匹配到对应的队列,由队列的监听消费者接收消息消费;
//生产者向交换机发送消息并给它一个RoutingKey
@Test
public void send(){
rabbitTemplate.convertAndSend(RabbitMQConfig.MRKAY_EXECHANGE,"mrkay.show01","routingkey为mrkay.show01");
rabbitTemplate.convertAndSend(RabbitMQConfig.MRKAY_EXECHANGE,"mrkay.show02","routingkey为mrkay.show02");
rabbitTemplate.convertAndSend(RabbitMQConfig.MRKAY_EXECHANGE,"mrkay.show03","routingkey为mrkay.show03");
rabbitTemplate.convertAndSend(RabbitMQConfig.MRKAY_EXECHANGE,"mrkay.show04","routingkey为mrkay.show04");
rabbitTemplate.convertAndSend(RabbitMQConfig.MRKAY_EXECHANGE,"amrkay.show","routingkey为mrkay.ashow");
}
//MQ配置类中交换机与队列绑定指定的RoutingKey
@Bean
public Binding queueExechange(@Qualifier("mrkay_queue") Queue queue, @Qualifier("mrkay_exechange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("mrkay.#").noargs();
}
不难发现:
发送消息的时指定"门牌号"和MQ配置类中交换机和队列绑定的"门牌号"进行了模糊匹配,
只有"mrkay."开头并且"."后面只有一个单词才能匹配上,"amrkay.show"这个"门牌号"根本匹配不上所以消息是不能发送出去的;