MQ简要介绍
MQ全称为Message Queue,即消息队列。“消息队列”是在消息的传输过程中保存消息的容器。它是典型的:生产者、消费者模型。
生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息。
因为消息的生产和消费都是异步的,而且只关心消息的发送和接收,没有业务逻辑的侵入,这样就实现了生产者和消费者的解耦。
MQ主要用途
1.异步任务处理
高并发环境下,由于来不及同步处理,请求往往会发生堵塞,比如说,大量的insert,update之类的请求同时到达MySQL,直接导致无数的行锁表锁,甚至最后请求会堆积过多,从而触发too many connections错误。将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。减少了应用程序的响应时间。
2.流量削峰
通过使用消息队列,我们可以异步处理请求,从而缓解系统的压力。
3.程序解耦
MQ相当于一个中介,生产方通过MQ与消费方交互,它将应用程序进行解耦合。
RabbitMQ主要结构
Exchange:消息队列交换机,按一定的规则将消息路由转发到某个队列,对消息进行过虑。
Queue:消息队列,存储消息的队列,消息到达队列并转发给指定的消费者
Producer:消息生产者,即生产方客户端,生产方客户端将消息发送
Consumer:消息消费者,即消费方客户端,接收MQ转发的消息。
下面开始实战
springBoot整合RabbitMQ
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.配置配置项
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
3.定义RabbitMQ配置类,配置交换机和队列,并将交换机和队列完成绑定
package com.example.myproject.config;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Description: rabbitMQ config
* date: 2022/12/19 14:35
* @author: siyu.kuang
* @since JDK 1.8
*/
@Configuration
public class RabbitmqConfig {
public static final String Direct_EMAIL_QUEUE = "direct_email_queue";
public static final String Direct_SMS_QUEUE = "direct_sms_queue";
public static final String DIRECT_EXCHANGE = "direct.exchange";
public static final String EMAIL_KEY = "email";
public static final String SMS_KEY = "sms";
/**
* 声明Direct交换机
* @return
*/
@Bean(DIRECT_EXCHANGE)
public Exchange directExchange(){
return ExchangeBuilder.directExchange(DIRECT_EXCHANGE).durable(true).build();
}
/**
* 声明队列
* new Queue(QUEUE_EMAIL,true,false,false)
* durable="true" 持久化 rabbitmq重启的时候不需要创建新的队列
* auto-delete 表示消息队列没有在使用时将被自动删除 默认是false
* exclusive 表示该消息队列是否只在当前connection生效,默认是false
*/
@Bean(Direct_EMAIL_QUEUE)
public Queue directEmailQueue(){
return new Queue(Direct_EMAIL_QUEUE);
}
@Bean(Direct_SMS_QUEUE)
public Queue directSmsQueue(){
return new Queue(Direct_SMS_QUEUE);
}
/**
* ROUTING_KEY_SMS队列绑定交换机,指定routingKey
* @param queue
* @param exchange
* @return
*/
@Bean
public Binding bindingDirectEmail(@Qualifier(Direct_EMAIL_QUEUE) Queue queue,
@Qualifier(DIRECT_EXCHANGE) Exchange exchange){
return BindingBuilder.bind(queue).to(exchange).with(EMAIL_KEY).noargs();
}
@Bean
public Binding bindingDirectSMS(@Qualifier(Direct_SMS_QUEUE) Queue queue,
@Qualifier(DIRECT_EXCHANGE) Exchange exchange){
return BindingBuilder.bind(queue).to(exchange).with(SMS_KEY).noargs();
}
}
这里简单演示Direct类型的交换机,并在交换机上绑定了两个队列。(fanout类型,topic类型的交换机其实大差不差,就是消息分发的机制不同)
4.消息发送
package com.example.myproject.utils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import static com.example.myproject.config.RabbitmqConfig.*;
@Component
public class MqSendHandler {
@Autowired
RabbitTemplate rabbitTemplate;
public void sendDirect(String rotingKey,String message){
rabbitTemplate.convertAndSend(DIRECT_EXCHANGE,rotingKey,message);
}
}
controller层调用消息发送方法
package com.example.myproject.controller;
import com.example.myproject.utils.MqSendHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MqController {
@Autowired
MqSendHandler mqSendHandler;
@RequestMapping("/mqSend")
public String mqSend(String routingKey,String message){
mqSendHandler.sendDirect(routingKey,message);
return "ok";
}
}
5.消息接收
package com.example.myproject.utils;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import static com.example.myproject.config.RabbitmqConfig.*;
/**
* Description:
* date: 2022/12/19 14:01
* @author: siyu.kuang
* @since JDK 1.8
*/
@Component
public class MqReceiveHandler {
/**
* direct交换机邮件队列监听
* @param msg
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = Direct_EMAIL_QUEUE, durable = "true"),
exchange = @Exchange(
value = DIRECT_EXCHANGE,
ignoreDeclarationExceptions = "true"
),
key = {EMAIL_KEY}))
public void recDirectEmail(String msg){
System.out.println(" direct[邮件服务] received : " + msg + "!");
}
/**
* direct交换机短信队列监听
* @param msg
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = Direct_SMS_QUEUE, durable = "true"),
exchange = @Exchange(
value = DIRECT_EXCHANGE,
ignoreDeclarationExceptions = "true"
),
key = {SMS_KEY}))
public void recDirectSms(String msg){
System.out.println(" direct[短信服务] received : " + msg + "!");
}
}
6启动程序,调用消息发送接口
用postMan调用接口,并传递routingKey为email
查看程序控制台输出
用postMan调用接口,并传递routingKey为sms
查看控制台输出
到这里就完成springboot操作RabbitMQ的操作了啦!
其它类型交换机一样操作