springboot整合RabbitMQ
一、介绍
MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。
-
MQ特点: MQ是消费-生产者模型的一个典型的代表,一端往消息队列中不断写入消息,而另一端则可以读取或者订阅队列中的消息。MQ和JMS类似,但不同的是JMS是SUN JAVA消息中间件服务的一个标准和API定义,而MQ则是遵循了AMQP协议的具体实现和产品。
-
含义:RabbitMQ是一个在AMQP基础上完成的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。
-
概念:RabbitMQ是流行的开源消息队列系统,用erlang语言开发。RabbitMQ是AMQP(高级消息队列协议)的标准实现。如果不熟悉AMQP,直接看RabbitMQ的文档会比较困难。不过它也只有几个关键概念,这里简单介绍。
RabbitMQ的结构图如下:
Broker:简单来说就是消息队列服务器实体:
- Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
- Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
- Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
- Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
- vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
- producer:消息生产者,就是投递消息的程序。
- consumer:消息消费者,就是接受消息的程序。
- channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。
消息队列的使用过程大概如下:
- 客户端连接到消息队列服务器,打开一个channel。
- 客户端声明一个exchange,并设置相关属性。
- 客户端声明一个queue,并设置相关属性。
- 客户端使用routing key,在exchange和queue之间建立好绑定关系。
- 客户端投递消息到exchange。
exchange接收到消息后,就根据消息的key和已经设置的binding,进行消息路由,将消息投递到一个或多个队列里。
exchange也有几个类型,完全根据key进行投递的叫做Direct交换机,例如,绑定时设置了routing
key为”abc”,那么客户端提交的消息,只有设置了key为”abc”的才会投递到队列。对key进行模式匹配后进行投递的叫做Topic交换机,符号#
匹配一个或多个词,符号*
匹配正好一个词。例如”abc.#”匹配”abc.def.ghi”,”abc.*”只匹配”abc.def”。还有一种不需要key的,叫做Fanout交换机,它采取广播模式,一个消息进来时,投递到与该交换机绑定的所有队列。
————————————————
版权声明:以上为CSDN博主「默-存」的原创文章,遵循CC 4.0 BY-SA版权协议,转载附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/typ1805/article/details/82835318
二、引入RabbitMQ配置工作
pom
<!--RabbitMq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
yml
spring:
#配置rabbitmq
rabbitmq:
host: 127.0.0.1 #服务地址
port: 5672 #端口号
username: guest #账号
password: guest #密码
config:
/**
*为了让保存到消息队列中的对象能以json的格式展示需要
*/
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
三、基本使用
SpringBoot项目中可以使用RabbitTemplate
直接对RabbitMQ进行操作。
@Autowired
private RabbitTemplate rabbitTemplate;
一、队列——Queue
生产者发送的消息,根据先后顺便被保存到消息队列中,等待着被消费者取出,一旦一条消息被取出之后,这条消息在队列中就会被删除。
多个消费者可以订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。
新建队列的几个属性:
- name:队列名字
- durable:是否支持持久化,默认true
- exclusive:表示该消息队列是否只在当前connection中生效,默认是false
- autoDelete:没有消息和连接时是否自动删除,默认时false
//添加一个名为hello的队列
@Bean
public Queue helloQueue() {
/**
* name:队列名字
* durable:是否支持持久化,默认true
* exclusive:表示该消息队列是否只在当前connection中生效,默认是false
* autoDelete:没有消息和连接时是否自动删除,默认时false
*/
Queue hello = new Queue("hello",true,false,true);
return hello;
}
添加消息进队列:因为没有交换器,所以绑定key(routingKey)和队列名字(queue)相同
/**
* 直接把消息发送到hello队列中
* (这里的hello实际上是routingKey,因为没有交换器,所以直接匹配名字为“hello”的队列)
*/
@GetMapping("/sendHello")
public R sendHello(){
String message = "hello:helloQueue";
log.info("发送消息到hellod队列:"+message);
rabbitTemplate.convertAndSend("hello",message);
return R.ok();
}
项目启动执行sendHello方法可以发现队列hello已经加到rabbitmq中且有一条消息
取出消息有两种方式:
- 手动取出消息
/**
* 从hello队列中取出发送的消息
*/
@GetMapping("/getHello")
public R getHello(){
Object helloMessage = rabbitTemplate.receiveAndConvert("hello");
log.info("从hello队列中取出发送的消息:"+helloMessage);
return R.ok(helloMessage);
}
- 通过监听队列自动获取消息——@RabbitListener
@RabbitListener(queues = "hello")
public void getHelloLer(String helloMessage){
log.info("监听hello队列获取消息:"+helloMessage);
}
二、交换器
生产者可以通过把消息放给交换器,交换器根据一定的绑定规则,当一条消息发送过来的时候传递给一个或者多个队列,使每个被传递的队列中都有这条消息。
新建交换器时的几个属性
- name:交换器的名字
- durable:是否支持持久化,默认为true
- autoDelete:不使用时是否自动删除,默认为false
交换器分为四个类型:
类型一、direct
direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。
//==========================direct==========================================================
/**
* 直连交换器
*/
@Bean
public DirectExchange directExchange(){
/**
* name:交换器的名字
* durable:是否支持持久化,默认为true
* autoDelete:不使用时是否自动删除,默认为false
*/
return new DirectExchange("directExchange",true,true);
}
/**
* user队列
*/
@Bean
public Queue userQueue() {
return new Queue("user",true,false,true);
}
/**
* user2队列
*/
@Bean
public Queue userQueue2() {
return new Queue("user2",true,false,true);
}
/**
* 把user队列绑定到 directExchange 交换器中 routingKey 为 user
* @param userQueue user队列,注意参数名要和user队列的方法名统一
* @param directExchange 直连交换器,注意参数名要和直连交换器方法名统一
*/
@Bean
public Binding bindingDirectUserQueue(Queue userQueue,DirectExchange directExchange){
return BindingBuilder.bind(userQueue).to(directExchange).with("user_routingKey");
}
/**
* 把user2队列绑定到 directExchange 交换器中 routingKey 为 user
* @param userQueue2 user队列,注意参数名要和user队列的方法名统一
* @param directExchange 直连交换器,注意参数名要和直连交换器方法名统一
*/
@Bean
public Binding bindingDirectUserQueue2(Queue userQueue2,DirectExchange directExchange){
return BindingBuilder.bind(userQueue2).to(directExchange).with("user_routingKey");
}
启动项目可以发现绑定关系已经生效