安装
拉取镜像
docker pull rabbitmq:3.8.9-management
启动
docker run -d --name rabbitmq3.7.7 -p 5672:5672 -p 15672:15672 -v `pwd`/data:/var/lib/rabbitmq --hostname myRabbit -e RABBITMQ_DEFAULT_VHOST=my_vhost -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin 68898be27496
-d 后台运行容器;
–name 指定容器名;
-p 指定服务运行的端口(5672:应用访问端口;15672:控制台Web端口号);
-v 映射目录或文件;
–hostname 主机名(RabbitMQ的一个重要注意事项是它根据所谓的 “节点名称” 存储数据,默认为主机名);
-e 指定环境变量;(RABBITMQ_DEFAULT_VHOST:默认虚拟机名;RABBITMQ_DEFAULT_USER:默认的用户名;RABBITMQ_DEFAULT_PASS:默认用户名的密码)
登录
用户管理
设置用户角色权限
给 root用户添加administrator
rabbitmqctl set_user_tags root administrator
登录
队列权限
入门
消息发送
导入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.10.0</version>
</dependency>
代码
public class SendMsg {
public static void main(String[] args) throws IOException, TimeoutException {
//创建连接工厂对象
ConnectionFactory factory = new ConnectionFactory();
//设置RabbitMQ的主机IP
factory.setHost("192.168.11.137");
//设置端口
factory.setPort(5672);
//设置访问用户名
factory.setUsername("root");
//设置访问密码
factory.setPassword("root");
//定义连接对象
Connection connection=null;
//定义通道对象
Channel channel=null;
//实例化连接对象
connection=factory.newConnection();
//实例化通道对象
channel=connection.createChannel();
//准备发送的消息
String msg="我的RabbitMQ测试消息";
/**
* 参数1: 定义队列名称
* 参数2: 是否为持久化队列
* 参数3: 是否排外 true 表示这个队列只允许一个消费者监听
* 参数4: 是否自动删除队列 true 当前队列没有消息,也没有消费者连接时 会自动删除队列
* 参数5: 队列的属性,通常为 null
*/
channel.queueDeclare("myQueue",true,false,false,null);
/**
* 发送消息
* 参数1: 交换机类型 ,为空表示不指定
* 参数2: 队列名称或者RoutingKey 如果不指定交换机名称则此参数表示队列名称,如果指定,则表示RoutingKey
* 参数3: 消息属性
* 参数4: 发送的具体消息
*/
channel.basicPublish("","myQueue",null,msg.getBytes("utf-8"));
System.out.println("消息发送成功");
//关闭连接
if(channel!=null)
{
channel.close();
}
if(connection!=null)
{
connection.close();
}
}
}
测试
代码运行中可能出现异常
#method<connection.close>(reply-code=530, reply-text=NOT_ALLOWED - vhost / not found, class-id=10, method-id=40)
需要给用户配置访问host权限
rabbitmqctl set_permissions -p / root '.*' '.*' '.*'
也可以在管理页面上配置
消息接收
导入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.10.0</version>
</dependency>
代码
package com.tx;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ReceiveMsg {
public static void main(String[] args) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
//创建连接对象
Connection connection=null;
connection=factory.newConnection();
//创建通道对象
Channel channel=null;
channel=connection.createChannel();
//创建队列
channel.queueDeclare("myQueue",true,false,false,null);
/**
* 接收消息
* 参数1: 接收的队列名
* 参数2: 消息是否自动确认,true: 自动确认接收完消息后会把消息从队列中移除
* 参数3: 为消息接收者的标签,用于当多个消费者同时监听一个队列时,区分消费者,通常为空字符串
* 参数4: 消息接收的回调方法,对返回消息的业务处理
*/
channel.basicConsume("myQueue", 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.print("接收消息:");
System.out.println(new String(body,"utf-8"));
}
});
}
}
接收消息中资源不关闭会一直监听队列
消息路由交换机类型
driect
消息发送
package com.tx.direct;
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 SendMsg {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
Connection connection =factory.newConnection();
Channel channel = connection.createChannel();
/**
* 声明队列
*/
channel.queueDeclare("directQueue",true,false,false,null);
/**
* 声明交换机
* 参数1: 交换机名称
* 参数2: 交换机类型
* 参数3: 是否为持久化交换机
* 注意: 这个代码可有可无 如果交换机已经存在,则不需要再次声明
*/
channel.exchangeDeclare("myDirectExchange","direct",true);
/**
* 交换机与队列绑定
* 参数1: 队列名称
* 参数2: 交换机名称
* 参数3: routingkey
*/
channel.queueBind("directQueue","myDirectExchange","routingkey");
//发布消息
String directMsg="测试direct消息发送";
channel.basicPublish("myDirectExchange","routingkey",null,directMsg.getBytes("utf-8"));
System.out.println("消息发送成功");
//关闭资源
channel.close();
connection.close();
}
}
消息接收
package com.tx.direct;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ReceiveMsg {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare("directQueue",true,false,false,null);
//声明交换机
channel.exchangeDeclare("myDirectExchange","direct",true);
//队列与交换机绑定
channel.queueBind("directQueue","myDirectExchange","routingkey");
/**
* 接收消息
*/
channel.basicConsume("directQueue",true,"",new DefaultConsumer(channel)
{
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(consumerTag);
System.out.println(new String(body,"utf-8"));
}
});
}
}
Fanout
消息接收
fanout需要消费者先进行监听,如果先发送会发生消息丢失
package com.tx.fanout;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ReceiceMsg02 {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
/**
* 由于fanout类型的交换机的消息类似于广播的模式,他不需要绑定routingkey
* 而又可能会有多个消费者来接收这个交换机中的数据,因此我们创建队列时要创建一个
* 随机的队列名称
* 没有参数的queueDecliare方法会创建一个名字为随机的一个队列
* 这个队列的数据非持久化
* 是排外的(同时最多只允许一个消费者监听当前队列)
* 自动删除的 当没有任何消费者监听队列时,这个队列会自动删除
* getQueue() 用于获取这个队列的名称
*/
String queueName = channel.queueDeclare().getQueue();
//定义fanout交换机
channel.exchangeDeclare("myFanoutExchange","fanout",true);
//将随机命名队列绑定到交换机中
channel.queueBind(queueName,"myFanoutExchange","");
channel.basicConsume(queueName,true,"",new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("ReceiceMsg02接收消息"+new String(body,"utf-8"));
}
});
}
}
消息发送
public class SendMsg {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//定义交换机
channel.exchangeDeclare("myFanoutExchange","fanout",true);
String msg="测试fanout发送消息";
//发送消息,发送到fanout交换机中
channel.basicPublish("myFanoutExchange","",null,msg.getBytes());
channel.close();
connection.close();
}
}
Topic
消息接收1
package com.tx.topic;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ReceiveMsg01 {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare("myTopicQueue",true,false,false,null);
//声明交换机
channel.exchangeDeclare("myTopicExchenge","topic",true);
//绑定交换机与队列
//key.* 表示接收匹配routingkey为 key.后面只能有一个字符串 key.aa
channel.queueBind("myTopicQueue","myTopicExchenge","key.*");
//接收消息
channel.basicConsume("myTopicQueue",true,"",new DefaultConsumer(channel)
{
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("ReceiveMsg01接收消息"+new String(body,"utf-8"));
}
});
}
}
消息接收2
package com.tx.topic;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ReceiveMsg02 {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare("myTopicQueue",true,false,false,null);
//声明交换机
channel.exchangeDeclare("myTopicExchenge","topic",true);
//绑定交换机与队列
//key.# 表示routingkey后可以有多个字符串 key.aa.bb.cc
channel.queueBind("myTopicQueue","myTopicExchenge","key.#");
//接收消息
channel.basicConsume("myTopicQueue",true,"",new DefaultConsumer(channel)
{
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("ReceiveMsg02接收消息"+new String(body,"utf-8"));
}
});
}
}
消息发送
package com.tx.topic;
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 SendMsg {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
String msg="测试topic发送的消息";
channel.basicPublish("myTopicExchenge","key",null,msg.getBytes());
//关闭资源
channel.close();
connection.close();
}
}
消息事务
rabbitmq有两种方式解决事务问题
1.AMQP提供的事务机制解决
2.使用发送者确认模式解决
事务_AMPQ事务机制
主要有三个方法
channel.txSelect();//开启事务
channel.txRollback();//回滚事务
channel.txCommit();//提交事务
事务方法对消费者暂时不起作用
发送消息
package com.tx.directtx;
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 Sendmsg {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("myqueue",true,false,false,null);
channel.exchangeDeclare("mydiretc","direct",true);
channel.queueBind("myqueue","mydiretc","routingkey");
channel.txSelect();//开启事务
String msg="事务消息";
channel.basicPublish("mydiretc","routingkey",null,msg.getBytes());
if(false)
{
channel.txRollback();//回滚事务
}
else
{
channel.txCommit();//提交事务
}
}
}
接收消息
package com.tx.directtx;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ReceiveMsg {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("myqueue",true,false,false,null);
channel.exchangeDeclare("mydiretc","direct",true);
channel.queueBind("myqueue","mydiretc","routingkey");
channel.basicConsume("myqueue",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,"utf-8"));
}
});
}
}
事务_发送者确认模式
使用方法开启事务channel.confirmSelect();
发送者确认模式_普通确认
使用方法channel.waitForConfirms();
代码
package com.tx.directtx.sendconfim;
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 SendMsg {
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
//定义队列
channel.queueDeclare("confimqueue",true,false,false,null);
channel.exchangeDeclare("dirctExc","direct",true);
channel.queueBind("confimqueue","dirctExc","routingkey");
//启动发送者确认模式
channel.confirmSelect();
String msg="消息确认模式——普通模式";
channel.basicPublish("dirctExc","routingkey",null,msg.getBytes());
/**
* 阻塞线程等待服务返回响应,用于是否消费发送成功,如果服务确认消息已经发送完成则返回true 否则返回false
* 可以为这个方法指定一个参数,用于确定我们需要等待服务确认的超时时间
* 如果超过了指定的时间以后则会抛出异常InterruptedException,表示服务器出现问题需要补发消息
* 或者将消息缓存到redis中稍后利用定时任务补发
* 无论是返回false还是抛出异常消息都有可能发送成功可能没成功,(可能发送成功但是返回消息时程序出问题导致返回false)
* 消息补发:使用递归或者redis+定时任务来完成补发
*/
boolean b = channel.waitForConfirms();
System.out.println("b:"+b+"--"+(b?"消息成功":"消息失败"));
}
}
发送者确认模式_批量确认
需要使用方法waitForConfirmsOrDie
package com.tx.directtx.sendconfim;
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 Sendbatch {
public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
//定义队列
try {
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("confimqueue",true,false,false,null);
channel.exchangeDeclare("dirctExc","direct",true);
channel.queueBind("confimqueue","dirctExc","routingkey");
//开启发送者确认模式
channel.confirmSelect();
for(int i=0;i<=100;i++)
{
String msg="发送者确认模式——批量模式"+i;
channel.basicPublish("dirctExc","routingkey",null,msg.getBytes());
}
/**
* waitForConfirmsOrDie 批量消息确认,他会同时向服务中确认之前通道中发送的所有消息是否已经全部成功写入
* 这个方法没有任何返回值,如果服务器中有一条消息没有能够成功或向服务器发送确认时服务不可访问都被认定为
* 消息确认失败,可能有消息没有发送成功,需要进行消息补发
* 如果无法向服务器获取确认信息那么方法就会抛出InterruptedException异常。这时就需要补发消息到队列
* waitForConfirmsOrDie(long time)指定参数 用户等待服务器的确认时间,如果超出这个时间也会抛出异常
* 表示需要补发消息
* 注意:
* 批量消息确认的速度比普通的消息确认要快 ,但是一旦出现了消息补发的情况,我们不能确定具体‘
* 是哪条没有发送完成,需要将本次的发送的所有消息进行补发
*/
channel.waitForConfirmsOrDie();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
发送者确认模式_监听确认
使用方法 channel.addConfirmListener(new ConfirmListener();
package com.tx.directtx.sendconfim;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class SendListener {
public static void main(String[] args) {{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
//定义队列
try {
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("confimqueue",true,false,false,null);
channel.exchangeDeclare("dirctExc","direct",true);
channel.queueBind("confimqueue","dirctExc","routingkey");
//开启发送者确认模式
channel.confirmSelect();
for(int i=0;i<100;i++)
{
String msg="发送者确认模式——批量模式"+i;
channel.basicPublish("dirctExc","routingkey",null,msg.getBytes());
}
/**
* 添加异步监听
*/
channel.addConfirmListener(new ConfirmListener() {
/**
* 消息确认成功以后的回调方法
* @param l 为确认消息的编号 从1开始 递增
* @param b 为当前消息是否确认了多个
*/
public void handleAck(long l, boolean b) throws IOException {
System.out.println("消息编号:"+l+"是否确认了多个:"+b);
}
/**
*消息没有确认的回调方法
* @param l 没有被确认的编号 从1开始 递增
* @param b 是否确认了多个
*/
public void handleNack(long l, boolean b) throws IOException {
}
});
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
}
消费者确认模式
package com.tx.directtx.receiveConfig;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Receive {
public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
//定义队列
try {
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("confimqueue",true,false,false,null);
channel.exchangeDeclare("dirctExc","direct",true);
channel.queueBind("confimqueue","dirctExc","routingkey");
//开启发送者确认模式
channel.confirmSelect();
/**
* 参数2: 为消息确认机制,true 表示自动消息确认,确认以后从队列中移除消息
* 当设置为true时,如果我们只是接收消息还没有来得及处理(比如当前应用奔溃或者服务器宕机),由于消息自动确认这个消息会
* 在接收完成后自动从队列中移除,这就会丢失消息,所以不会设置成true
* 设置为fasle 为手动确认消息
*
*/
channel.basicConsume("confimqueue",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,"utf-8"));
//获取消息编号
long deliveryTag = envelope.getDeliveryTag();
System.out.println("消息编号"+envelope.getDeliveryTag());
Channel channel1 = this.getChannel();
/**
* 手动确认消息,确认以后表示当前消息已经成功处理,需要从消息队列中移除
* 参数1:为消息的序号
* 参数2: 为是否确认多个,如果为true表示需要确认小与等于当前编号的所有消息,false是单个确认
*/
channel1.basicAck(deliveryTag,true);
}
});
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
防重复处理
package com.tx.directtx.receiveConfig;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Receive {
public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.11.137");
factory.setPort(5672);
factory.setUsername("root");
factory.setPassword("root");
//定义队列
try {
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("confimqueue",true,false,false,null);
channel.exchangeDeclare("dirctExc","direct",true);
channel.queueBind("confimqueue","dirctExc","routingkey");
//启动事务
channel.txSelect();
/**
* 参数2: 为消息确认机制,true 表示自动消息确认,确认以后从队列中移除消息
* 当设置为true时,如果我们只是接收消息还没有来得及处理(比如当前应用奔溃或者服务器宕机),由于消息自动确认这个消息会
* 在接收完成后自动从队列中移除,这就会丢失消息,所以不会设置成true
* 设置为fasle 为手动确认消息
*
*/
channel.basicConsume("confimqueue",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,"utf-8"));
//获取消息编号
long deliveryTag = envelope.getDeliveryTag();
System.out.println("消息编号"+envelope.getDeliveryTag());
Channel channel1 = this.getChannel();
/**
* 手动确认消息,确认以后表示当前消息已经成功处理,需要从消息队列中移除
* 参数1:为消息的序号
* 参数2: 为是否确认多个,如果为true表示需要确认小与等于当前编号的所有消息,false是单个确认
*/
channel1.basicAck(deliveryTag,true);
channel1.txCommit();
}
});
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
防止重复处理
Springboot整合rabbitmq
direct发送消息
导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>
配置application.yml
编写配置类
需要在配置类中提供交换机对象,队列对象,绑定对象
代码
package com.tx.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
//定义交换机
@Bean
public DirectExchange getdirectExchange()
{
System.out.println("定义交换机");
return new DirectExchange("boot-direct-exchange");
}
//定义队列
@Bean
public Queue getQueue()
{
System.out.println("定义队列");
return new Queue("boot-direct-queue");
}
//把交换机与队列绑定
@Bean
public Binding getBinding(DirectExchange directExchange,Queue queue)
{
return BindingBuilder.bind(queue).to(directExchange).with("routingkey");
}
}
编写发送消息方法
package com.tx.service.serviceimpl;
import com.tx.service.SendService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("sendService")
public class SendServiceImpl implements SendService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendMsg(String msg)
{
/**
* 参数1: 交换机名称
* 参数2: routing
* 参数3: 发送消息object
*/
rabbitTemplate.convertAndSend("boot-direct-exchange","routingkey",msg);
}
}
调用这个方法就可以发送消息到配置的队列中
direct接收消息
以上方法可以实现接收消息,但是无法持续的监听队列接收消息
使用注解RabbitListener来设置监听方法
package com.tx.service;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class DirectReceiveService {
/**
* 这个方法会对boot-direct-queue进行监听,因为交换机与队列绑定设置了routingkey所以只需要监听队列即可
* 参数只有一个接收的消息,解决消息会自动从队列中移除
* @param msg
*/
@RabbitListener(queues={"boot-direct-queue"})
public void directReceive(String msg)
{
System.out.println(msg);
}
/**
* 使用手动确认消息
* @param channel
* @param message
*/
@RabbitListener(queues={"boot-direct-queue"})
public void directReceive1(String msg,Channel channel, Message message) throws IOException {
System.out.println("消费者获取消息"+msg);
//手动移除消息
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
}
Fanout接收消息
package com.tx.service;
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.Service;
@Service
public class FanoutRecriveService {
@RabbitListener(bindings=
{
@QueueBinding(
value = @Queue,exchange = @Exchange(name ="boot-fanout-exchange",type = "fanout")
)
})
public void getMessages1(String msg)
{
System.out.println("消费者接收消息1:"+msg);
}
@RabbitListener(bindings=
{
@QueueBinding(//定义随机的队列进行监听
value = @Queue,exchange = @Exchange(name ="boot-fanout-exchange",type = "fanout")
)
})
public void getMessages2(String msg)
{
System.out.println("消费者接收消息2:"+msg);
}
}
Fanout发送消息
需要在配置类在先定义fanout交换机对象
发送消息的代码
topic接收消息
package com.tx.service;
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.Service;
@Service
public class TopicReceiveService {
@RabbitListener(bindings = {
@QueueBinding(value = @Queue(name = "boot-topic-queue"),
exchange = @Exchange(name = "boot-topic-exchange",type = "topic"),
key = "aa"
)
})
public void getMessage1(String messgae)
{
System.out.println("消费者1接收消息:"+messgae);
}
@RabbitListener(bindings = {
@QueueBinding(value = @Queue(name = "boot-topic-queue"),
exchange = @Exchange(name = "boot-topic-exchange",type = "topic"),
key = "aa.*"
)
})
public void getMessage2(String messgae)
{
System.out.println("消费者2接收消息:"+messgae);
}
@RabbitListener(bindings = {
@QueueBinding(value = @Queue(name = "boot-topic-queue"),
exchange = @Exchange(name = "boot-topic-exchange",type = "topic"),
key = "aa.#"
)
})
public void getMessage3(String messgae)
{
System.out.println("消费者3接收消息:"+messgae);
}
}
topic发送消息
需要在配置类中配置fanout交换机
发送消息代码
RabbitMQ集群
启动3个rabbitmq
启动第一个
docker run --hostname rabbitmq01 --name myrabbitmq01 -p 5672:5672 15672:75672 rabbitmq:3.8.9-management
启动第二个 使用容器互联
docker run -d --hostname rabbitmq02 --name myrabbitmq02 -p 5673:5672 -p 15673:15672 --link myrabbitmq01:rabbitmq01 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.8.9-management
启动第三个 使用linl容器互联第一个与第二个
docker run -d --hostname rabbitmq03 --name myrabbitmq03 -p 5674:5672 -p 15674:15672 --link myrabbitmq02:rabbitmq02 --link myrabbitmq01:rabbitmq01 -e RABBITMQ_ERLANG_COOKIE='rabbitcookie' rabbitmq:3.8.9-management
三个启动完成后进入容器进行加入节点
进入页面查看
springboot连接集群
rabbitmq:
addresses: 127.0.0.1:6605,127.0.0.1:6606,127.0.0.1:6705 #指定client连接到的server的地址,多个以逗号分隔(优先取addresses,然后再取host)
# port:
##集群配置 addresses之间用逗号隔开
# addresses: ip:port,ip:port
password: admin
username: 123456
virtual-host: / # 连接到rabbitMQ的vhost
requested-heartbeat: #指定心跳超时,单位秒,0为不指定;默认60s
publisher-confirms: #是否启用 发布确认
publisher-reurns: # 是否启用发布返回
connection-timeout: #连接超时,单位毫秒,0表示无穷大,不超时
cache:
channel.size: # 缓存中保持的channel数量
channel.checkout-timeout: # 当缓存数量被设置时,从缓存中获取一个channel的超时时间,单位毫秒;如果为0,则总是创建一个新channel
connection.size: # 缓存的连接数,只有是CONNECTION模式时生效
connection.mode: # 连接工厂缓存模式:CHANNEL 和 CONNECTION
listener:
simple.auto-startup: # 是否启动时自动启动容器
simple.acknowledge-mode: # 表示消息确认方式,其有三种配置方式,分别是none、manual和auto;默认auto
simple.concurrency: # 最小的消费者数量
simple.max-concurrency: # 最大的消费者数量
simple.prefetch: # 指定一个请求能处理多少个消息,如果有事务的话,必须大于等于transaction数量.
simple.transaction-size: # 指定一个事务处理的消息数量,最好是小于等于prefetch的数量.
simple.default-requeue-rejected: # 决定被拒绝的消息是否重新入队;默认是true(与参数acknowledge-mode有关系)
simple.idle-event-interval: # 多少长时间发布空闲容器时间,单位毫秒
simple.retry.enabled: # 监听重试是否可用
simple.retry.max-attempts: # 最大重试次数
simple.retry.initial-interval: # 第一次和第二次尝试发布或传递消息之间的间隔
simple.retry.multiplier: # 应用于上一重试间隔的乘数
simple.retry.max-interval: # 最大重试时间间隔
simple.retry.stateless: # 重试是有状态or无状态
template:
mandatory: # 启用强制信息;默认false
receive-timeout: # receive() 操作的超时时间
reply-timeout: # sendAndReceive() 操作的超时时间
retry.enabled: # 发送重试是否可用
retry.max-attempts: # 最大重试次数
retry.initial-interval: # 第一次和第二次尝试发布或传递消息之间的间隔
retry.multiplier: # 应用于上一重试间隔的乘数
retry.max-interval: #最大重试时间间隔
需要在控制页面添加