没有使用MQ:
- 系统的耦合性越高,容错性就越低,可维护性就越低。
没有使用MQ:
使用MQ:
小结:
系统引入的外部依赖越多,系统稳定性越差。一旦 MQ 宕机,就会对业务造成影响。如何保证MQ的高可用?
MQ 的加入大大增加了系统的复杂度,以前系统间是同步的远程调用,现在是通过 MQ 进行异步调用。如何保证消息没有被重复消费?怎么处理消息丢失情况?那么保证消息传递的顺序性?
A 系统处理完业务,通过 MQ 给B、C、D三个系统发消息数据,如果 B 系统、C 系统处理成功,D 系统处理失败。如何保证消息数据处理的一致性?
小结
既然 MQ 有优势也有劣势,那么使用 MQ 需要满足什么条件呢?
2007年,Rabbit 技术公司基于 AMQP 标准开发的 RabbitMQ 1.0 发布。RabbitMQ 采用 Erlang 语言开发。Erlang 语言由 Ericson 设计,专门为开发高并发和分布式系统的一种语言,在电信领域使用广泛。
RabbitMQ 基础架构如下图:
RabbitMQ 提供了 6 种工作模式:简单模式、work queues、Publish/Subscribe 发布与订阅模式、Routing 路由模式、Topics 主题模式、RPC 远程调用模式(远程调用,不太算 MQ;暂不作介绍)。
官网对应模式介绍:https://www.rabbitmq.com/getstarted.html
小结
上传文件:
在线安装依赖环境:
yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz
# 安装
rpm -ivh erlang-18.3-1.el7.centos.x86_64.rpm
如果出现如下错误
说明gblic 版本太低。我们可以查看当前机器的gblic 版本
shell strings /lib64/libc.so.6 | grep GLIBC
使用yum更新安装依赖
sudo yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make -y
下载rpm包
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-utils-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-static-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-common-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-devel-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-headers-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-x86_64/glibc-2.17-55.fc20/nscd-2.17-55.el6.x86_64.rpm &
安装rpm包
sudo rpm -Uvh *-2.17-55.el6.x86_64.rpm --force --nodeps
安装完毕后再查看glibc版本,发现glibc版本已经到2.17了
strings /lib64/libc.so.6 | grep GLIBC
# 安装
rpm -ivh socat-1.7.3.2-1.1.el7.x86_64.rpm --force --nodeps
# 安装
rpm -ivh rabbitmq-server-3.6.5-1.noarch.rpm
启动rabbitMQ
# 开启管理界面
rabbitmq-plugins enable rabbitmq_management
# 修改默认配置信息
vi /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin/rabbit.app
# 比如修改密码、配置等等,例如:loopback_users 中的 <<"guest">>,只保留guest
service rabbitmq-server start # 启动服务
service rabbitmq-server stop # 停止服务
service rabbitmq-server restart # 重启服务
192.168.101.22是本机虚拟机ip地址
RabbitMQ在安装好后,可以访问http://ip地址:15672
;其自带了guest/guest的用户名和密码;如果需要创建自定义用户;那么也可以登录管理界面后,如下操作:
1、 超级管理员(administrator)
可登陆管理控制台,可查看所有的信息,并且可以对用户,策略(policy)进行操作。
2、 监控者(monitoring)
可登陆管理控制台,同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)
3、 策略制定者(policymaker)
可登陆管理控制台, 同时可以对policy进行管理。但无法查看节点的相关信息(上图红框标识的部分)。
4、 普通管理者(management)
仅可登陆管理控制台,无法看到节点信息,也无法对策略进行管理。
5、 其他
无法登陆管理控制台,通常就是普通的生产者和消费者。
像mysql拥有数据库的概念并且可以指定用户对库和表等操作的权限。RabbitMQ也有类似的权限管理;在RabbitMQ中可以虚拟消息服务器Virtual Host,每个Virtual Hosts相当于一个相对独立的RabbitMQ服务器,每个VirtualHost之间是相互隔离的。exchange、queue、message不能互通。 相当于mysql的db。Virtual Name一般以/开头。
6.2.1. 创建Virtual Hosts
6.2.2. 设置Virtual Hosts权限
cd /usr/share/doc/rabbitmq-server-3.6.5/
cp rabbitmq.config.example /etc/rabbitmq/rabbitmq.config
service rabbitmq-server restart
需求:使用简单模式完成消息传递
pom.xml (这里生产者和消费者的依赖是一样的)
<dependencies>
<dependency>
<groupId>com.rabbitmqgroupId>
<artifactId>amqp-clientartifactId>
<version>5.6.0version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.0version>
<configuration>
<source>1.8source>
<target>1.8target>
configuration>
plugin>
plugins>
build>
package com.itheima.producer;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
//简单模式
//发送消息
public class Producer_HelloWorld {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建队列Queue 暂时不用交换机
/*
String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map arguments)
1.queue 队列名称
2.durable 是否持久化,当mq重启之后,还在
3.exclusive:
*是否独占:只能有一个消费者监听队列
*当connection关闭时,是否删除队列
4.autoDelete: 是否自动删除,当没有consumer时,自动删除掉
5.arguments: 参数
*/
//如果没有一个名字为hello_world的队列,则会创建队列,如果有则不会创建
channel.queueDeclare("hello_world",true,false,false,null);
//6.发送消息
/*
String exchange, String routingKey, boolean mandatory, byte[] body
参数:
1. exchange:交换机名称,简单模式下交换机会使用默认的 ""
2. routingKey: 路由名称
3. props: 配置信息
4. body: 发送消息数据
*/
String body="hello rabbitmq----";
channel.basicPublish("","hello_world",null,body.getBytes());
//7.释放资源
/*channel.close();
connection.close();*/
}
}
package com.itheima.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer_HelloWorld {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建队列Queue 暂时不用交换机
/*
String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map arguments)
1.queue 队列名称
2.durable 是否持久化,当mq重启之后,还在
3.exclusive:
*是否独占:只能有一个消费者监听队列
*当connection关闭时,是否删除队列
4.autoDelete: 是否自动删除,当没有consumer时,自动删除掉
5.arguments: 参数
*/
//如果没有一个名字为hello_world的队列,则会创建队列,如果有则不会创建
channel.queueDeclare("hello_world",true,false,false,null);
//6.接收消息
/*
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck: 是否自动确认
3. callback: 回调对象
*/
Consumer consumer=new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
1.consumerTag:标识
2.envelope:获取一些信息。交换机,路由key...
3.properties: 配置信息
4.body: 数据
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("consumerTag:"+consumerTag);
System.out.println("exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);
System.out.println("body:"+new String(body));//byte数组转string字符串
}
};
channel.basicConsume("hello_world",true,consumer);
//关闭资源?不要,因为消费者要监听
}
}
效果如下:
上述的入门案例中其实使用的是如下的简单模式:
Work Queues 与入门程序的简单模式的代码几乎是一样的。可以完全复制,并多复制一个消费者进行多个消费者同时对消费消息的测试。
Producer_WorkQueues
package com.itheima.producer;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
//简单模式
//发送消息
public class Producer_WorkQueues {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建队列Queue 暂时不用交换机
/*
String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map arguments)
1.queue 队列名称
2.durable 是否持久化,当mq重启之后,还在
3.exclusive:
*是否独占:只能有一个消费者监听队列
*当connection关闭时,是否删除队列
4.autoDelete: 是否自动删除,当没有consumer时,自动删除掉
5.arguments: 参数
*/
//如果没有一个名字为hello_world的队列,则会创建队列,如果有则不会创建
channel.queueDeclare("work_queues",true,false,false,null);
//6.发送消息
/*
String exchange, String routingKey, boolean mandatory, byte[] body
参数:
1. exchange:交换机名称,简单模式下交换机会使用默认的 ""
2. routingKey: 路由名称
3. props: 配置信息
4. body: 发送消息数据
*/
for (int i = 1; i <=10; i++) {
String body=i+"hello rabbitmq----";
channel.basicPublish("","work_queues",null,body.getBytes());
}
//7.释放资源
/*channel.close();
connection.close();*/
}
}
Consumer_WorkQueues1
package com.itheima.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer_WorkQueues1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建队列Queue 暂时不用交换机
/*
String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map arguments)
1.queue 队列名称
2.durable 是否持久化,当mq重启之后,还在
3.exclusive:
*是否独占:只能有一个消费者监听队列
*当connection关闭时,是否删除队列
4.autoDelete: 是否自动删除,当没有consumer时,自动删除掉
5.arguments: 参数
*/
//如果没有一个名字为hello_world的队列,则会创建队列,如果有则不会创建
channel.queueDeclare("work_queues",true,false,false,null);
//6.接收消息
/*
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck: 是否自动确认
3. callback: 回调对象
*/
Consumer consumer=new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
1.consumerTag:标识
2.envelope:获取一些信息。交换机,路由key...
3.properties: 配置信息
4.body: 数据
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag:"+consumerTag);
System.out.println("exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);*/
System.out.println("body:"+new String(body));//byte数组转string字符串
}
};
channel.basicConsume("work_queues",true,consumer);
//关闭资源?不要,因为消费者要监听
}
}
Consumer_WorkQueues2
package com.itheima.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer_WorkQueues2 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建队列Queue 暂时不用交换机
/*
String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map arguments)
1.queue 队列名称
2.durable 是否持久化,当mq重启之后,还在
3.exclusive:
*是否独占:只能有一个消费者监听队列
*当connection关闭时,是否删除队列
4.autoDelete: 是否自动删除,当没有consumer时,自动删除掉
5.arguments: 参数
*/
//如果没有一个名字为hello_world的队列,则会创建队列,如果有则不会创建
channel.queueDeclare("work_queues",true,false,false,null);
//6.接收消息
/*
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck: 是否自动确认
3. callback: 回调对象
*/
Consumer consumer=new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
1.consumerTag:标识
2.envelope:获取一些信息。交换机,路由key...
3.properties: 配置信息
4.body: 数据
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag:"+consumerTag);
System.out.println("exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);*/
System.out.println("body:"+new String(body));//byte数组转string字符串
}
};
channel.basicConsume("work_queues",true,consumer);
//关闭资源?不要,因为消费者要监听
}
}
注意:先运行消费者1和消费者2,再运行生产者
结果如下:消费者1消费消息序号 1,3,5,7,9
消费者2消费消息序号 2,4,6,8,10
在订阅模型中,多了一个 Exchange 角色,而且过程略有变化:
Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与 Exchange 绑定,或者没有符合路由规则的队列,那么消息会丢失!
生产者Producer_PubSub
package com.itheima.producer;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
//发布订阅模式
//发送消息
public class Producer_PubSub {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
exchangeDeclare
(String exchange, 交换机名称
BuiltinExchangeType type, 交换机类型 枚举类型
DIRECT("direct"), :定向
FANOUT("fanout"), :扇形(广播),发送消息到每一个与之绑定的队列
TOPIC("topic"),:通配符方式
HEADERS("headers");参数匹配
boolean durable, 是否持久化
boolean autoDelete, 是否自动删除
boolean internal, 内部使用一般false
Map arguments) 参数列表
*/
String exchangeName="test_fanout";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);
//6.创建两个队列
String queue1Name="test_fanout_queue1";
String queue2Name="test_fanout_queue2";
/*
String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map arguments)
1.queue 队列名称
2.durable 是否持久化,当mq重启之后,还在
3.exclusive:
*是否独占:只能有一个消费者监听队列
*当connection关闭时,是否删除队列
4.autoDelete: 是否自动删除,当没有consumer时,自动删除掉
5.arguments: 参数
*/
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7,绑定队列和交换机
/*
queueBind(String queue, String exchange, String routingKey)
参数:
1.queue: 队列名称
2.exchange:交换机
3.routingKey:路由键:绑定规则
如果交换机的类型为fanout,routingKey设置为""
*/
channel.queueBind(queue1Name,exchangeName,"");
channel.queueBind(queue2Name,exchangeName,"");
//8.发送消息
String body="日志信息:张三调用了findAll方法...日志级别:info";
channel.basicPublish(exchangeName,"",null,body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
}
Consumer_PubSub1
package com.itheima.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer_PubSub1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.队列已经声明一次了,这里不用再声明队列
String queue1Name="test_fanout_queue1";
String queue2Name="test_fanout_queue2";
//6.接收消息
/*
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck: 是否自动确认
3. callback: 回调对象
*/
Consumer consumer=new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
1.consumerTag:标识
2.envelope:获取一些信息。交换机,路由key...
3.properties: 配置信息
4.body: 数据
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag:"+consumerTag);
System.out.println("exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);*/
System.out.println("body:"+new String(body));//byte数组转string字符串
System.out.println("将日志信息打印到控制台");
}
};
channel.basicConsume(queue1Name,true,consumer);
//关闭资源?不要,因为消费者要监听
}
}
Consumer_PubSub2
package com.itheima.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer_PubSub2 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.队列已经声明一次了,这里不用再声明队列
String queue1Name="test_fanout_queue1";
String queue2Name="test_fanout_queue2";
//6.接收消息
/*
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck: 是否自动确认
3. callback: 回调对象
*/
Consumer consumer=new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
1.consumerTag:标识
2.envelope:获取一些信息。交换机,路由key...
3.properties: 配置信息
4.body: 数据
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag:"+consumerTag);
System.out.println("exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);*/
System.out.println("body:"+new String(body));//byte数组转string字符串
System.out.println("将日志信息保存数据库");
}
};
channel.basicConsume(queue2Name,true,consumer);
//关闭资源?不要,因为消费者要监听
}
}
运行结果:
交换机需要与队列进行绑定,绑定之后;一个消息可以被多个消费者都收到。
发布订阅模式与工作队列模式的区别:
工作队列模式不用定义交换机,而发布/订阅模式需要定义交换机
发布/订阅模式的生产方是面向交换机发送消息,工作队列模式的生产方是面向队列发送消息(底层使用默认交换机)
发布/订阅模式需要设置队列和交换机的绑定,工作队列模式不需要设置,实际上工作队列模式会将队列绑 定到默认的交换机
Producer_Routing
package com.itheima.producer;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
//Routing
//发送消息
public class Producer_Routing {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
exchangeDeclare
(String exchange, 交换机名称
BuiltinExchangeType type, 交换机类型 枚举类型
DIRECT("direct"), :定向
FANOUT("fanout"), :扇形(广播),发送消息到每一个与之绑定的队列
TOPIC("topic"),:通配符方式
HEADERS("headers");参数匹配
boolean durable, 是否持久化
boolean autoDelete, 是否自动删除
boolean internal, 内部使用一般false
Map arguments) 参数列表
*/
String exchangeName="test_direct";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT,true,false,false,null);
//6.创建两个队列
String queue1Name="test_direct_queue1";
String queue2Name="test_direct_queue2";
/*
String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map arguments)
1.queue 队列名称
2.durable 是否持久化,当mq重启之后,还在
3.exclusive:
*是否独占:只能有一个消费者监听队列
*当connection关闭时,是否删除队列
4.autoDelete: 是否自动删除,当没有consumer时,自动删除掉
5.arguments: 参数
*/
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7,绑定队列和交换机
/*
queueBind(String queue, String exchange, String routingKey)
参数:
1.queue: 队列名称
2.exchange:交换机
3.routingKey:路由键:绑定规则
如果交换机的类型为fanout,routingKey设置为""
*/
//队列1的绑定 error
channel.queueBind(queue1Name,exchangeName,"error");
//队列2的绑定 info,error,warning
channel.queueBind(queue2Name,exchangeName,"info");
channel.queueBind(queue2Name,exchangeName,"error");
channel.queueBind(queue2Name,exchangeName,"warning");
//8.发送消息
String body="日志信息:张三调用了delete方法出错误了...日志级别:error";
channel.basicPublish(exchangeName,"error",null,body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
}
Consumer_Routing1
package com.itheima.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer_Routing1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.队列已经声明一次了,这里不用再声明队列
String queue1Name="test_direct_queue1";
String queue2Name="test_direct_queue2";
//6.接收消息
/*
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck: 是否自动确认
3. callback: 回调对象
*/
Consumer consumer=new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
1.consumerTag:标识
2.envelope:获取一些信息。交换机,路由key...
3.properties: 配置信息
4.body: 数据
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag:"+consumerTag);
System.out.println("exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);*/
System.out.println("body:"+new String(body));//byte数组转string字符串
System.out.println("将日志信息打印到控制台");
}
};
channel.basicConsume(queue2Name,true,consumer);
//关闭资源?不要,因为消费者要监听
}
}
Consumer_Routing2
package com.itheima.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer_Routing2 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.队列已经声明一次了,这里不用再声明队列
String queue1Name="test_direct_queue1";
String queue2Name="test_direct_queue2";
//6.接收消息
/*
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck: 是否自动确认
3. callback: 回调对象
*/
Consumer consumer=new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
1.consumerTag:标识
2.envelope:获取一些信息。交换机,路由key...
3.properties: 配置信息
4.body: 数据
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag:"+consumerTag);
System.out.println("exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);*/
System.out.println("body:"+new String(body));//byte数组转string字符串
System.out.println("将日志信息存储到数据库");
}
};
channel.basicConsume(queue1Name,true,consumer);
//关闭资源?不要,因为消费者要监听
}
}
运行结果
Producer_Topics
package com.itheima.producer;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
//发送消息
public class Producer_Topics {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
exchangeDeclare
(String exchange, 交换机名称
BuiltinExchangeType type, 交换机类型 枚举类型
DIRECT("direct"), :定向
FANOUT("fanout"), :扇形(广播),发送消息到每一个与之绑定的队列
TOPIC("topic"),:通配符方式
HEADERS("headers");参数匹配
boolean durable, 是否持久化
boolean autoDelete, 是否自动删除
boolean internal, 内部使用一般false
Map arguments) 参数列表
*/
String exchangeName="test_topic";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,false,null);
//6.创建两个队列
String queue1Name="test_topic_queue1";
String queue2Name="test_topic_queue2";
/*
String queue, boolean durable, boolean exclusive, boolean autoDelete,
Map arguments)
1.queue 队列名称
2.durable 是否持久化,当mq重启之后,还在
3.exclusive:
*是否独占:只能有一个消费者监听队列
*当connection关闭时,是否删除队列
4.autoDelete: 是否自动删除,当没有consumer时,自动删除掉
5.arguments: 参数
*/
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7,绑定队列和交换机
/*
queueBind(String queue, String exchange, String routingKey)
参数:
1.queue: 队列名称
2.exchange:交换机
3.routingKey:路由键:绑定规则
如果交换机的类型为fanout,routingKey设置为""
*/
//routing key:系统的名称,日志级别
//--需求:所有error级别的日志存入数据库,所有order系统的日志存入数据库
channel.queueBind(queue1Name,exchangeName,"#.error");
channel.queueBind(queue1Name,exchangeName,"order.*");
channel.queueBind(queue2Name,exchangeName,"*.*");
//8.发送消息
String body="日志信息:张三调用了findAll方法...日志级别:info";
channel.basicPublish(exchangeName,"order.info",null,body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
}
Consumer_Topic1
package com.itheima.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer_Topic1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.队列已经声明一次了,这里不用再声明队列
String queue1Name="test_topic_queue1";
String queue2Name="test_topic_queue2";
//6.接收消息
/*
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck: 是否自动确认
3. callback: 回调对象
*/
Consumer consumer=new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
1.consumerTag:标识
2.envelope:获取一些信息。交换机,路由key...
3.properties: 配置信息
4.body: 数据
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag:"+consumerTag);
System.out.println("exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);*/
System.out.println("body:"+new String(body));//byte数组转string字符串
System.out.println("将日志信息存入数据库");
}
};
channel.basicConsume(queue1Name,true,consumer);
//关闭资源?不要,因为消费者要监听
}
}
Consumer_Topic2
package com.itheima.consumer;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer_Topic2 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory=new ConnectionFactory();
//2.设置参数
factory.setHost("192.168.101.22");//ip地址 默认localhost
factory.setPort(5672);//端口 默认值5672
factory.setVirtualHost("/itcast");//虚拟机默认值 /虚拟机
factory.setUsername("heima");//用户名 默认guest
factory.setPassword("heima");//密码 默认guest
//3.创建连接 connection
Connection connection = factory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.队列已经声明一次了,这里不用再声明队列
String queue1Name="test_topic_queue1";
String queue2Name="test_topic_queue2";
//6.接收消息
/*
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck: 是否自动确认
3. callback: 回调对象
*/
Consumer consumer=new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
1.consumerTag:标识
2.envelope:获取一些信息。交换机,路由key...
3.properties: 配置信息
4.body: 数据
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
/* System.out.println("consumerTag:"+consumerTag);
System.out.println("exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);*/
System.out.println("body:"+new String(body));//byte数组转string字符串
System.out.println("将日志信息打印到控制台");
}
};
channel.basicConsume(queue2Name,true,consumer);
//关闭资源?不要,因为消费者要监听
}
}
需求:使用 Spring 整合 RabbitMQ
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.1.7.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.amqpgroupId>
<artifactId>spring-rabbitartifactId>
<version>2.1.8.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.1.7.RELEASEversion>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.0version>
<configuration>
<source>1.8source>
<target>1.8target>
configuration>
plugin>
plugins>
build>
rabbitmq.properties
rabbitmq.host=192.168.101.22
rabbitmq.port=5672
rabbitmq.username=heima
rabbitmq.password=heima
rabbitmq.virtual-host=/itcast
spring-rabbitmq-producer.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<context:property-placeholder location="classpath:rabbitmq.properties"/>
<rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
port="${rabbitmq.port}"
username="${rabbitmq.username}"
password="${rabbitmq.password}"
virtual-host="${rabbitmq.virtual-host}"/>
<rabbit:admin connection-factory="connectionFactory"/>
<rabbit:queue id="spring_queue" name="spring_queue" auto-declare="true"/>
<rabbit:queue id="spring_fanout_queue_1" name="spring_fanout_queue_1" auto-declare="true"/>
<rabbit:queue id="spring_fanout_queue_2" name="spring_fanout_queue_2" auto-declare="true"/>
<rabbit:fanout-exchange id="spring_fanout_exchange" name="spring_fanout_exchange" auto-declare="true">
<rabbit:bindings>
<rabbit:binding queue="spring_fanout_queue_1"/>
<rabbit:binding queue="spring_fanout_queue_2"/>
rabbit:bindings>
rabbit:fanout-exchange>
<rabbit:queue id="spring_topic_queue_star" name="spring_topic_queue_star" auto-declare="true"/>
<rabbit:queue id="spring_topic_queue_well" name="spring_topic_queue_well" auto-declare="true"/>
<rabbit:queue id="spring_topic_queue_well2" name="spring_topic_queue_well2" auto-declare="true"/>
<rabbit:topic-exchange id="spring_topic_exchange" name="spring_topic_exchange" auto-declare="true">
<rabbit:bindings>
<rabbit:binding pattern="heima.*" queue="spring_topic_queue_star"/>
<rabbit:binding pattern="heima.#" queue="spring_topic_queue_well"/>
<rabbit:binding pattern="itcast.#" queue="spring_topic_queue_well2"/>
rabbit:bindings>
rabbit:topic-exchange>
<rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
beans>
ProducersTest
package com.itheima;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-rabbitmq-producer.xml")
public class ProducersTest {
//1.注入rabbitTemplate
@Autowired
private RabbitTemplate rabbitTemplate;
//简单模式
@Test
public void testHelloWorld(){
//2.发送消息
rabbitTemplate.convertAndSend("spring_queue","hello world spring...");
}
//发送fanout消息
@Test
public void testFanout(){
//2.发送消息
rabbitTemplate.convertAndSend("spring_fanout_exchange","","spring fanout...");
}
//发送topics消息
@Test
public void testTopic(){
//2.发送消息
rabbitTemplate.convertAndSend("spring_topic_exchange","heima.hehe.haha","spring topic...");
}
}
测试:分别运行测试方法,结果如下图
rabbitmq.properties
rabbitmq.host=192.168.101.22
rabbitmq.port=5672
rabbitmq.username=heima
rabbitmq.password=heima
rabbitmq.virtual-host=/itcast
spring-rabbitmq-consumer.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<context:property-placeholder location="classpath:rabbitmq.properties"/>
<rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
port="${rabbitmq.port}"
username="${rabbitmq.username}"
password="${rabbitmq.password}"
virtual-host="${rabbitmq.virtual-host}"/>
<bean id="springQueueListener" class="com.itheima.rabbitmq.listener.SpringQueueListener"/>
<rabbit:listener-container connection-factory="connectionFactory" auto-declare="true">
<rabbit:listener ref="springQueueListener" queue-names="spring_queue"/>
rabbit:listener-container>
beans>
SpringQueueListener
package com.itheima.rabbitmq.listener;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
public class SpringQueueListener implements MessageListener {
@Override
public void onMessage(Message message) {
//打印消息
System.out.println(new String(message.getBody()));
}
}
ConsumerTest
package com.itheima;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-rabbitmq-consumer.xml")
public class ConsumerTest {
@Test
public void test(){
boolean flag=true;
while(true){
}
}
}
测试:
<rabbit:queue id="spring_queue" name="spring_queue" auto-declare="true"/>
direct exchange补充
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.4.RELEASEversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
dependencies>
RabbitMQConfig
package com.itheima.rabbitmq.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;
@Configuration
public class RabbitMQConfig {
public static final String EXCHANGE_NAME="boot_topic_exchange";
public static final String QUEUE_NAME="boot_quque";
//1.交换机
@Bean("bootExchange")
public Exchange bootExchange(){
return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
}
//2.队列 Queue
@Bean("bootQueue")
public Queue bootQueue(){
return QueueBuilder.durable(QUEUE_NAME).build();
}
//3.队列和交换机的绑定关系 binding
/*
1.知道哪个队列
2.知道哪个交换机
3.routing key
*/
@Bean
public Binding bindQueueExange(@Qualifier("bootQueue") Queue queue,@Qualifier("bootExchange") Exchange exchange){
return BindingBuilder.bind(queue).to(exchange).with("boot.#").noargs();
}
}
ProducerApplication
package com.itheima;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ProducerApplication.class);
}
}
application.yml
# 配置rabbitmq的基本信息 IP端口 username passwordspring:
spring:
rabbitmq:
host: 192.168.101.22
port: 5672
virtual-host: /itcast
username: heima
password: heima
ProducerTest
package com.itheima.test;
import com.itheima.rabbitmq.config.RabbitMQConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
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
@RunWith(SpringRunner.class)
public class ProducerTest {
//1.注入rabbitTemplate
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSend(){
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME,"boot.haha","boot mq hello---");
}
}
测试:运行Junit Test
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
package com.itheima;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConsumerSpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerSpringbootApplication.class, args);
}
}
RabbitMQListener
package com.itheima;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class RabbitMQListener {
@RabbitListener(queues = "boot_quque")
public void ListenerQueue(Message message){
System.out.println(new String(message.getBody()));
}
}
application.yml
# 配置rabbitmq的基本信息 IP端口 username passwordspring:
spring:
rabbitmq:
host: 192.168.101.22
port: 5672
virtual-host: /itcast
username: heima
password: heima
pom.xml
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.4.RELEASEversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-amqpartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
dependencies>
运行ConsumerSpringbootApplication, 消费者拿到消息