一,RabbitMQ简介
MQ:MQ就是消息队列,“消息队列”是在消息的传输过程中保存消息的容器。 MQ种类有很多,RabbitMQ是MQ的一种。
RabbitMQ:
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。
负责项目之间消息的接收和存取 在集群时进行集群内信息传递
MQ作用:
-
解耦 ()为两个后端项目间传值提供实现
-
流量削峰
-
消息发布和管理
二,RabbitMQ安装
基于docker 20.10.23安装
docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:3.9.9-management
management:是有web管理页面的镜像
访问:http://172.19.186.149:15672 本机访问
远程访问后面是5672结尾
用户名和密码都是guest
注意防火墙
没有自启动的化,每次进项目要自己start启动
三,RabbitMQ基本概念
4.1、Queues(队列)
是用来存放消息的队列。
4.2点对点消息
从一个生产者生产消息,到一个消费者消费消息,这种方式就是点对点消息。相当于发短信,张三给李四发短信,张三就是生产者,李四就是消费者。例子举得极端,大家理解意思。
4.3、主题
订阅,是一个生产者生产消息,很多订阅了这个生产者的消费者都可以接收到消息。相当于公众号推送文章。
4.4、Exchange(交换器)
和硬件交换机有类似的含义,交换机可以帮助消息找到对应的队列,将消息送达到队列中。
4.5、创建交换机
4.6绑定队列
将交换机和队列建立关系。同样很少通过页面创建。
填写队列名
下一个是路由键名称,路由键名称是交换机名+点+队列名
4.7队列发送信息常用的三种类型
-
direct:直连,点对点,A发给B。默认的模式。是通过路由键找到队列,是精准匹配,如果没有符合规则的消息会被废弃。
-
fanout:扇形,点对面,A发给BCD ,可以收也可以废弃。不通过路由键找队列,通过交换机和队列的绑定找到队列。
-
topic:主题,点对面,A发给BCD ,BCD 都接收消息。是通过路由键找队列,模糊匹配方式,通过通配符(*)模糊匹配所有符合规则的,如果没有符合规则的消息会被废弃。
还有一种是headers,是废弃的类型,效率比较低。类似于direct的方式。
4.8路由键
帮助消息能找到对应的交换机和队列。
一个字符串,规约上定义格式是XXX.XXX.XXX,以点为分隔符的形式定义的字符串。一般是交换机名+队列名
4.9Connections&Channels(连接和信道)
也可以通过依赖进行链接信道;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.1.10.RELEASE</version>
</dependency>
要发送消息到队列,自然要有一个连接才可以,消息时通过Connections连接到RabbitMQ的,然后通过信道找到交换机和队列。
4.10虚拟主机
添加自己的用户
添加主机;点击set permission会自动添加本机
是RabbitMQ虚拟出的虚拟机,可以为多个项目服务。
在多项目用到RabbitMQ时,可以创建多个虚拟主机,每个虚拟主机都是沙盒隔离的,相互不会有影响,即使某个虚拟主机宕机,也不会影响到其它的虚拟主机。
四,SpringBoot整合RabbitMQ
官方文档:
1、添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.10.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>
2、开启RabbitMQ
在启动类上添加注解,以开启RabbitMQ。
@EnableRabbit
3、添加配置文件
spring:
rabbitmq:
host: 192.168.1.239
port: 5672
username: guest
password: guest
guest是游客账号,只能在本机访问,外部访问需要创建一个新的账户。
5672端口号是程序访问的端口,15672是web访问的端口。
3.1【怎样创建新的用户】
【注意:用户名admin,密码123456】
【创建用户成功,如下:】
【点击进入,新建用户 admin里】
【设置admin用户的虚拟主机,/ 表示所有。】
4、创建交换机、队列和绑定
1、创建交换机
package com.jr.test;
@SpringBootTest(classes = SpringBootMain.class) //SpringBootMain 是SpringBoot项目的启动类
@Slf4j
@SuppressWarnings("all")
@RunWith(SpringRunner.class) //SpringRunner 是依赖中的系统类,如果Test导的是junit包里,需要加@RunWith注解
public class RabbitMqTest {
@Autowired
private AmqpAdmin amqpAdmin;
/**
* String name:交换机名称
* boolean durable:是否持久化
* boolean autoDelete:是否自动删除
*/
@Test
public void createExchange() {
String name = "helloworld";
boolean durable = true;
boolean autoDelete = false;
DirectExchange directExchange = new DirectExchange(name, durable, autoDelete);
amqpAdmin.declareExchange(directExchange);
log.info("create exchanges {}", "hello");
}
}
运行Test进行创建
2、创建队列
/**
* 队列名称
* 是否持久化
* 是否排他
* 是否自动删除
*/
@Test
public void createQueue() {
Queue queue = new Queue("helloworld-queue", true, false, false);
String queueName = amqpAdmin.declareQueue(queue);
log.info("create queue {}", queueName);
}
3、创建绑定
/**
* 目的地名字(就是队列的名字)
* 绑定类型,交换机或队列
* 交换机名称
* 路由键
* 参数(很少使用)
*/
@Test
public void createBinding() {
Binding binding = new Binding("helloworld-queue", Binding.DestinationType.QUEUE, "helloworld", "helloworld.queue", null);
amqpAdmin.declareBinding(binding);
log.info("create binding routeKey {}", "helloworld.queue");
}
总体代码:
package com.jr.test;
import com.jr.SpringMain;
import com.jr.entry.Emp;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest(classes = SpringMain.class) //SpringBootMain 是SpringBoot项目的启动类
@Slf4j
@SuppressWarnings("all")
@RunWith(SpringRunner.class) //SpringRunner 是依赖中的系统类,如果Test导的是junit包里,需要加@RunWith注解
public class RabbitMQtest {
@Autowired
private AmqpAdmin amqpAdmin;
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* String name:交换机名称
* boolean durable:是否持久化
* boolean autoDelete:是否自动删除
*/
@Test
public void createExchange() {
String name = "helloworld";
boolean durable = true;
boolean autoDelete = false;
DirectExchange Exchange = new DirectExchange(name, durable, autoDelete);
amqpAdmin.declareExchange(Exchange);
log.info("创建交换机成功");
}
@Test
public void createQueues(){
Queue queue=new Queue("rabbitQueue",true,false,false);
amqpAdmin.declareQueue(queue);
log.info("创建队列成功");
}
@Test
public void createbinding(){
Binding binding=new Binding("rabbitQueue",Binding.DestinationType.QUEUE,"helloworld","helloworld.queue",null);
amqpAdmin.declareBinding(binding);
log.info("绑定成功");
}
@Test
public void sendMessage(){
rabbitTemplate.convertAndSend("helloworld", "helloworld.queue", "hello world cfff切切切切切切切切fff!");
}
@Test
public void sendObject(){
Emp user = new Emp();
user.setEmpno("zhangsan");
user.setEname("123456");
rabbitTemplate.convertAndSend("helloworld", "helloworld.queue", user);
log.info("发送对象信息成功");
}
}
五、发送消息
1、发送字符串
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 交换机名称
* 路由键
* 内容
*/
@Test
public void sendMessage(){
rabbitTemplate.convertAndSend("helloworld", "helloworld.queue", "hello world !");
}
不是常用功能,一般都会发送对象。
Messages填写多少就可以查看多少数据;需要手动进行修改
2、发送对象
1、添加配置类 不修改已有的配置文件而达到添加配置的效果
package com.jr.config;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyMqConfig {
//导入的是接口
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}
2、创建一个对象类
package com.jr.entry;
import lombok.Data;
@Data
public class User {
private String name;
private String password;
}
3、发送消息
/**
* 交换机名称
* 路由键
* 对象
*/
@Test
public void sendObject(){
User user = new User();
user.setName("zhangsan");
user.setPassword("123456");
rabbitTemplate.convertAndSend("helloworld", "helloworld.queue", user);
}
发送消息时参数传对象即可,根据配置类会自动转成JSON字符串。
六、接受消息
点对点类型进行传递信息,接受信息后,RabbitMQ页面中就不再显示发送到信息了
@RabbitListener
配置了注解的类一定要放到IoC容器中,参数类型要和发送的对象匹配上。
import org.jsoft.demo.vo.User;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
//创建监听类进行接受消息;配置后发送方一发送消息,自动接受
@Component
public class RabbitMqListener {
@RabbitListener(queues = {"helloworld-queue"})
public void getMessage(Message message, User user) { //设置接收的消息类型
System.out.println("--------------------------------------------------");
System.out.println("--------------------------------------------------");
System.out.println("--------------------------------------------------");
System.out.println("--------------------------------------------------");
System.out.println("--------------------------------------------------");
System.out.println("--------------------------------------------------");
System.out.println(user);
System.out.println("--------------------------------------------------");
System.out.println(message);
System.out.println("--------------------------------------------------");
System.out.println(new String(message.getBody()));
System.out.println("--------------------------------------------------");
System.out.println("--------------------------------------------------");
System.out.println("--------------------------------------------------");
System.out.println("--------------------------------------------------");
System.out.println("--------------------------------------------------");
System.out.println("--------------------------------------------------");
}
}