1. 使用前准备
1.1 添加依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.7.2</version>
</dependency>
1.2 配置
- 启动程序后,访问网址:http://localhost:15672/
- 登录:密码、账号默认:guest
- 为虚拟主机添加用户
- 为用户设置权限
2. 使用
2.1 第一种模型(直连)
一个生产者一个消费者
P:生产者,发送消息的程序
C:消费者,消息接收者,会一直等到消息的到来
quene:消息队列
代码示例:
- 生产者
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//此处注意的是连接用的端口15672,通信端口5672
connectionFactory.setUsername("ems");//用户名
connectionFactory.setPassword("ems");//密码
connectionFactory.setVirtualHost("/ems");//虚拟主机
Connection connection = connectionFactory.newConnection();//连接
//创建通道
Channel channel = connection.createChannel();
//参数1: 是否持久化 参数2:是否独占队列 参数3:是否自动删除 参数4:其他属性
channel.queueDeclare("hello", true, false, false, null);
channel.basicPublish("", "hello", null, "hello rabbitmq".getBytes());
channel.close();
connection.close();
- 消费者 注意:使用测试类不支持多线程
public static void main(String[] args) throws IOException, TimeoutException {
// 创建连接工程
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("ems");
connectionFactory.setPassword("ems");
connectionFactory.setVirtualHost("/ems");
// 创建链接
Connection connection = connectionFactory.newConnection();
// 创建通道
Channel channel = connection.createChannel();
// 通道绑定队列->和生产者参数要一样
channel.queueDeclare("hello", true, false, false, null);
/**
*消费消息
* 参数1.队列名
* 参数2.开始消息的自动确认机制
* 参数3.消息的回调接口
*/
channel.basicConsume("hello", true, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("body = " + new Stringbody(body));
}
});
// 不建议关闭,处于监听状态,消息过来方便消费
// channel.close();
// connection.close();
}
- 以上代码可以封装成工具类
public class RabbitMQUtils {
private static ConnectionFactory connectionFactory;
//类加载时候执行,只执行一次
static {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/ems");
connectionFactory.setUsername("ems");
connectionFactory.setPassword("ems");
}
/**
* 提供连接
*/
public static Connection getConnection() {
try {
return connectionFactory.newConnection();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 关闭连接
* 关闭通道
*/
public static void closeConnection(Channel channel, Connection connection) {
try {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.1.1 持久化
2.1.1.1 队列持久化
- 生产者
//第二个参数队列持久化
channel.queueDeclare("hello", true, false, false, null);
- 消费者 生产者的参数和消费者的参数保持一致
channel.queueDeclare("hello", true, false, false, null);
D:标识持久化
2.1.1.2 消息持久化
/**
* 参数1:交换机名称
* 参数2:队列名称
* 参数3:消息持久化MessageProperties.PERSISTENT_TEXT_PLAIN
* 参数4:发送消息的内容
*/
channel.basicPublish("", "hello", MessageProperties.PERSISTENT_TEXT_PLAIN, "hello rabbitmq".getBytes());
2.2 第二种模型(任务模型:work quene)
生产者的生产速度大于消费者的速度,则使用任务模型,一个生产者多个消费者。
2.2.1 默认消费者平均消费
消费者消费消息的数量和速度没有关系,消费者平均消费
- 生产者
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("work", true, false, false, null);
//发布消息
for (int i = 0; i < 10; i++) {
channel.basicPublish("", "work", null, (i + "hello").getBytes());
}
RabbitMQUtils.closeConnection(channel,connection);
}
- 消费者1
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.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 = RabbitMQUtils.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));
}
});
}
2.2.2 消息确认机制和能者多劳
自动确认机制:RatherMQ会将队列中的消息平均分配给消费者,然后消费者去消费,和消费时间没有关系,这样宕机会存在消息的丢失。
消费者一方的设置消息确认机制
//参数2:消息自动确认机制 true;一般使用不自动确认
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));
}
});
2.2.2.1 实现能者多劳
生产者不变,消费者变为:
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("work", true, false, false, null);
//保证每次只过来一个消息
channel.basicQos(1);
//参数2:消息自动确认机制
channel.basicConsume("work", false, new DefaultConsumer(channel) {
@SneakyThrows
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
Thread.sleep(2000);
System.out.println("消费者-2 " + new String(body));
/**
* 手动确认
* 参数1:手动确认消息标志
* 参数2:fasle每次确认1个消息,true:多个
*/
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
}
2.3 第三种模式(fanout广播)
注意:生产者的每条消息消费者都能消费,而不是分配的
- 生产者
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
/**
* 管道声明指定交换机
* 参数1:交换机名
* 参数2:交换机类型;fanout:广播
*/
channel.exchangeDeclare("logs", "fanout");
/**
* 发送消息
* 参数1:交换机名
* 参数2:路由key
* 参数3:消息持久化
* 参数4:消息内容
*/
channel.basicPublish("logs", "", null, "fanout messsage".getBytes());
RabbitMQUtils.closeConnection(channel, connection);
}
- 消费者
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//通道绑定交换机
channel.exchangeDeclare("logs", "fanout");
//临时队列
String queueName = channel.queueDeclare().getQueue();
/**
* 绑定交换机队列
* 参数1:队列名
* 参数2:交换机名
* 参数3: 路由key
*/
channel.queueBind(queueName, "logs", "");
//消费消息
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("消费者1-->" + new String(body));
}
});
}
2.4 第四种模式(Routing路由)
2.4.1 订阅模式->Direct
解释
- 队列与交换机的绑定不是任意绑定的,需要指定一个路由key(RoutingKey)
- 消息的发送方向交换机发送消息时也需要绑定RoutingKey
- 交换机不再把消息交给每个队列,而是根据RoutingKey判断,只有RoutingKey一样才会受到消息
说明:
- 交换机类型为Direct
- error、info为路由key,消费者1只能接收到error的消息;消费者2能接收到error、info的消息
- 生产者
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("logs_direct", "direct");
//发送消息
String routingKey = "info";
channel.basicPublish("logs_direct", routingKey, null, "这是路由模式下的订阅模式".getBytes());
RabbitMQUtils.closeConnection(channel,connection);
}
- 消费者1
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("logs_direct", "direct");
//创建一个临时队列
String queue = channel.queueDeclare().getQueue();
//绑定路由key
channel.queueBind(queue, "logs_direct", "error");
//消费者消费消息
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 static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("logs_direct", "direct");
//创建一个临时队列
String queue = channel.queueDeclare().getQueue();
//绑定路由key
channel.queueBind(queue, "logs_direct", "error");
channel.queueBind(queue, "logs_direct", "info");
//消费者消费消息
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));
}
});
}
2.4.2 订阅模式->Topoc
动态路由
- 使用通配符 *、#:
- *:代表一个
- #:代表多个。
- 生产者
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
//管道绑定交换机
channel.exchangeDeclare("topics", "topic");
//发布消息
String routingKey = "user.save";
channel.basicPublish("topics", routingKey, null, ("动态路由消息+routingKey:" + routingKey).getBytes());
RabbitMQUtils.closeConnection(channel, connection);
}
- 消费者1
public static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("topics", "topic");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//绑定交换机和队列,动态通配符形式绑定routingKey
channel.queueBind(queue, "topics", "user.*");
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 static void main(String[] args) throws IOException {
Connection connection = RabbitMQUtils.getConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare("topics", "topic");
//创建临时队列
String queue = channel.queueDeclare().getQueue();
//绑定交换机和队列,动态通配符形式绑定routingKey
channel.queueBind(queue, "topics", "user.#");
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->user.#:"+new String(body));
}
});
}