RabbitMQ入门教程
一、安装以及启动
- 安装(mac):
brew install rabbitmq
各个版本rabbitmq下载 - 启动方式1:
(1)进入目录下:cd /usr/local/Cellar/rabbitmq/3.6.6
(2)执行:sbin/rabbitmq-server
- 启动方式2*:
(1)终端执行:vi ~/.bashrc
vi ~/.zshrc
(2)添加环境变量:export PATH=$PATH:/usr/local/sbin
(3)启动mq:rabbitmq-server
- 客户端:
http://localhost:15672
(初始用户密码都是guest),显示如下界面安装启动成功:
二、第1种模型:hello world
最简单一对一关系的消费者生产者模型
1、管理页面加入新的用户和消费队列的虚拟机
添加用户:
添加虚拟主机:
2、创建java项目,引入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
</dependency>
3、发送消息到队列
/**
* 生产者
*/
@Test
public void produce() throws IOException, TimeoutException {
// mq连接服务器工厂对象
ConnectionFactory factory = new ConnectionFactory();
// 设置连接主机
factory.setHost( "127.0.0.1" );
// 设置端口
factory.setPort( 5672 );
// 设置连接虚拟主机
factory.setVirtualHost( "/ems" );
// 设置用户名密码
factory.setUsername( "ems" );
factory.setPassword( "ems" );
// 获取连接对象
Connection connection = factory.newConnection();
// 获取连接通道对象
Channel channel = connection.createChannel();
// 通道绑定对应的消息队列
// 参数1:队列名称 存在连接 不存在则创建
// 参数2:队列属否需要持久化 不持久化重启队列则会被删除
// 参数3:是否独占队列 true:只可当前通道访问 fasle:不独占队列
// 参数4:是否在消费完成后删除队列
// 参数5:额外参数
channel.queueDeclare("hello", false, false, false, null);
// 发布消息
// 参数1:交换机
// 参数2:发送队列
// 参数3:发布消息的属性
// 参数4:发布消息的内容
channel.basicPublish( "", "hello", null, "hello world11".getBytes() );
channel.close();
connection.close();
}
发送成功在管理界面的Queues标签页下会看到如下:
4、消费者
/**
* 一直监听消息队列的消息 发一条消息取一次
* @param args
* @throws IOException
* @throws TimeoutException
*/
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost( "127.0.0.1" );
factory.setPort( 5672 );
// 虚拟主机
factory.setVirtualHost( "/ems" );
factory.setUsername( "ems" );
factory.setPassword( "ems" );
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 绑定消息队列
channel.queueDeclare( "hello", false, false, false, null );
// 消费消息
// 参数1:消费那个队列的消息
// 参数2:开启消息的自动确认机制
// 参数3:消费消息的回掉接口
channel.basicConsume( "hello", true, new DefaultConsumer( channel ) {
/**
*
* @param consumerTag 标签
* @param envelope
* @param properties
* @param body 接收的消息队列的内容
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// 打印消息队列取出的内容
System.out.println(consumerTag + ":" + new String( body ));
}
} );
}
读取成功,获取到生产者发送的消息:
5、连接工具类
public class MqUtils {
private static ConnectionFactory connectionFactory;
static {
connectionFactory = new ConnectionFactory();
connectionFactory.setHost( "127.0.0.1" );
connectionFactory.setPort( 5672 );
connectionFactory.setVirtualHost( "/ems" );
connectionFactory.setUsername( "ems" );
connectionFactory.setPassword( "ems" );
}
/**
* 获取mq连接
* @return
*/
public static Connection getConnection() {
try {
return connectionFactory.newConnection();
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
return null;
}
/**
* 关闭通道和连接
* @param channel
* @param connection
*/
public static void closeChannelAndConnection(Channel channel, Connection connection){
try {
if(channel != null) channel.close();
if(connection != null) connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
6、API参数
三、第2种模型:平均消息模型
消费者1消费奇数,消费者2消费偶数
- 生产者:
public void sendMessage() throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare( "work", true, false, false, null );
for (int i = 0; i < 10; i++) {
channel.basicPublish( "", "work", MessageProperties.PERSISTENT_TEXT_PLAIN, (i + "work work").getBytes() );
}
MqUtils.closeChannelAndConnection( channel, connection );
}
- 消费者1:
/**
* 消费者1 消费13579....
* 消费者2 消费02468....
*
*/
public static void main(String[] args) throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare( "work", true, false, false, null );
channel.basicConsume( "work", true, new DefaultConsumer( channel ) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1:"+new String( body ));
}
});
}
- 消费者2:
public static void main(String[] args) throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare( "work", true, false, false, null );
channel.basicConsume( "work", true, new DefaultConsumer( channel ) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者2:"+new String( body ));
}
});
}
附加:消息确认机制 – 手动消息确认
public static void main(String[] args) throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
// 一次消费一条消息 ********增加的********
channel.basicQos( 1 );
channel.queueDeclare( "work", true, false, false, null );
// ********增加的******** channel.basicConsume( "work", 是否自动确认。。。。。。。。
channel.basicConsume( "work", false, new DefaultConsumer( channel ) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1:"+new String( body ));
// ********增加的********
// 手动确认 参数1:手动确认参数标示 参数2:是否开启多条消息确认
channel.basicAck( envelope.getDeliveryTag(), false );
}
});
}
四、第3种模型:广播消息模型
- 生产者
@SpringBootTest
public class ProduceTest {
@Test
public void sendMsg() throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
// 1.声明交换机 exchangeDeclare("交换机名称", "交换机类型");
channel.exchangeDeclare("logs", "fanout");
// 2.向交换机发送消息 basicPublish(交换机,路由key,。。 )
channel.basicPublish( "logs", "", null, "这是交换机中的消息".getBytes() );
MqUtils.closeChannelAndConnection( channel, connection );
}
}
- 消费者(可以有多个 代码一样)
@SpringBootTest
public class CustomerTest01 {
public static void main(String[] args) throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
// 1.声明一个交换机
channel.exchangeDeclare( "logs", "fanout" );
// 2.创建临时队列(消费队列都是临时的,减轻mq的负担)
String queue = channel.queueDeclare().getQueue();
// 3.绑定临时队列和交换机 queueBind( 队列, "交换机", "路由key" );
channel.queueBind( queue, "logs", "" );
channel.basicConsume( queue, true, new DefaultConsumer( channel ){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String( body ));
}
});
}
}
五、第4种模型:路由消息模型
该模型是基于广播模型的更加高级的用法,生产者生产消息会绑定一个路由key,交换机会发送消息给绑定同一路由的消费者
- 生产者:
@Test
public void sendMsg() throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
// 如果指定fanout(广播)路由是不生效的
// 指定路由模式
channel.exchangeDeclare( "logs_direct", "direct" );
// 绑定路由key,每条消息会被绑定同一路由的消费者接收
String routerKey = "router_key_error";
for (int i = 0; i < 10; i++) {
channel.basicPublish( "logs_direct", routerKey, null, ("这是路由发的消息 key:"+routerKey+" i:"+i).getBytes() );
}
MqUtils.closeChannelAndConnection( channel, connection );
}
- 消费者1:
public class CustomerTest01 {
public static void main(String[] args) throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
// 声明路由模式的交换机
channel.exchangeDeclare( "logs_direct", "direct" );
String queue = channel.queueDeclare().getQueue();
// 路由key
String routerKey = "router_key_error";
// 绑定交换机和路由key
channel.queueBind( queue, "logs_direct", routerKey );
channel.basicConsume( queue, true, new DefaultConsumer( channel ) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1:" + new String( body ));
}
} );
}
}
- 消费者2:
public class CustomerTest02 {
static String routerKey = "router_key_error";
public static void main(String[] args) throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare( "logs_direct", "direct" );
String queue = channel.queueDeclare().getQueue();
channel.queueBind( queue, "logs_direct", routerKey );
channel.basicConsume( queue, true, new DefaultConsumer( channel ) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者2:" + new String( body ));
}
} );
}
}
六、第5种模型:topic消息模型
*(星)可以代替一个词。
#(hash)可以代替零个或多个单词。
- 生产者
static String EXCHANGE_NAME = "topics";
@Test
public void sendMsg() throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
// topic模式 可以 '通配符' 模糊匹配
// auth.# 匹配多个 比如 auth.irs.compose 和 auth.irs都可以匹配
// auth.* 匹配单个 只能匹配auth.irs
channel.exchangeDeclare( EXCHANGE_NAME, "topic" );
// topic的路由key
String routerKey = "user.save";
for (int i = 0; i < 10; i++) {
channel.basicPublish( EXCHANGE_NAME, routerKey, null, ("这是路由发的消息 key:"+routerKey+" i:"+i).getBytes() );
}
MqUtils.closeChannelAndConnection( channel, connection );
}
- 消费者1
public class CustomerTest01 {
static String EXCHANGE_NAME = "topics";
// 通配符 匹配一个单词
static String ROUTER_KEY = "user.*";
public static void main(String[] args) throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare( EXCHANGE_NAME, "topic" );
String queue = channel.queueDeclare().getQueue();
channel.queueBind( queue, EXCHANGE_NAME, ROUTER_KEY );
channel.basicConsume( queue, true, new DefaultConsumer( channel ) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者1:" + new String( body ));
}
} );
}
}
- 消费者2
public class CustomerTest02 {
static String EXCHANGE_NAME = "topics";
// 所有user的
static String ROUTER_KEY = "user.#";
// 标示user前有一个单词,,user后面可以匹配多个单词
// static String ROUTER_KEY = "*.user.#";
public static void main(String[] args) throws IOException {
Connection connection = MqUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare( EXCHANGE_NAME, "topic" );
// 临时队列
String queue = channel.queueDeclare().getQueue();
channel.queueBind( queue, EXCHANGE_NAME, ROUTER_KEY );
channel.basicConsume( queue, true, new DefaultConsumer( channel ) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者2:" + new String( body ));
}
} );
}
}
七、SpringBoot整合RabbitMQ
1、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2、引入rabbitmq模版引擎
@Autowired
private RabbitTemplate rabbitTemplate;
3、hello world模型
生产者:
// hello world模型 convertAndSend(队列,消息)
rabbitTemplate.convertAndSend( "hello_api", "hello world" );
消费者:
@Component
@RabbitListener( queuesToDeclare = @Queue(value = "hello_api", durable = "false", exclusive = "false", autoDelete = "true"))
public class CutsomerTest {
@RabbitHandler
public void receivel(String message){
System.out.println("消息是:"+message);
}
}
4、平均模型
消费者:
// 平均消息模型 convertAndSend(队列,消息)
rabbitTemplate.convertAndSend( "work_api", "work model" );
生产者:
@RabbitListener( queuesToDeclare = @Queue(value = "work_api"))
public void getMsg1(String message){
System.out.println("消费1:"+message);
}
@RabbitListener( queuesToDeclare = @Queue(value = "work_api"))
public void getMsg2(String message){
System.out.println("消费2:"+message);
}
5、广播模型
生产者:
// 广播消息模型 convertAndSend(交换机,路由key,消息)
rabbitTemplate.convertAndSend( "logs_api", "", "public模型");
生产者:
@RabbitListener( bindings = {
// 声明一个临时队列
@QueueBinding(
value = @Queue, // 不指定名称标示创建临时队列
exchange = @Exchange(value = "logs_api", type = "fanout") // 绑定交换机
)
})
public void getMsg1(String message){
System.out.println("消费1:"+message);
}
@RabbitListener( bindings = {
// 声明一个临时队列
@QueueBinding(
value = @Queue, // 不指定名称标示创建临时队列
exchange = @Exchange(value = "logs_api", type = "fanout") // 绑定交换机
)
})
public void getMsg2(String message){
System.out.println("消费2:"+message);
}
6、路由模型
生产者:
// 路由消息模型 同上
rabbitTemplate.convertAndSend( "logs_direct_api", "error", "路由发送的消息" );
消费者:
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "logs_direct_api",type = "direct"),
key = {"info","error"} // 绑定info、error两个key键
)
})
public void getMsg_all(String message){
System.out.println("info_error"+message);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "logs_direct_api",type = "direct"),
key = {"error"}
)
})
public void getMsg_error(String message){
System.out.println("error"+message);
}
7、topic模型
生产者:
rabbitTemplate.convertAndSend( "logs_topic_api", "user.save", "topic发送的消息" );
消费者:
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "logs_topic_api",type = "topic"),
key = {"user.save","user.*"}
)
})
public void getMsg_all(String message){
System.out.println("\"user.save\",\"user.*\" "+message);
}
@RabbitListener(bindings = {
@QueueBinding(
value = @Queue,
exchange = @Exchange(value = "logs_topic_api",type = "topic"),
key = {"user.#.#"}
)
})
public void getMsg_error(String message){
System.out.println("user.# "+message);
}