消息中间件rabbitmq主要有四种模式:fanout广播、direct分食、topic主题订阅、header-不常用,代码都很类似,主要区别是创建消息主题时会区别声明exchangeDeclare(),还有消息接收后需要给producer一个确认消息

环境准备

  1. 服务准备
erlang用管理员权限安装并配置ERLANG_HOME和%ERLANG_HOME%\bin

rabbitmq用管理员权限安装并用管理权限打开的命令行执行如下
*\rabbitmq_server-3.9.2\sbin\rabbitmq-plugins.bat enable rabbitmq_management
net stop RabbitMQ
net start RabbitMQ
  1. rabbitmq服务开启
//用管理员权限使用命令行执行
net start RabbitMQ
  1. 服务启动截图
  2. 进入rabbitmq的消息监控页面
打开http://127.0.0.1:15672/并输入guest/guest
rabbitmq服务的默认端口是15672

代码示例

  • pom引入
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.7.1</version>
</dependency>
<!-- 使用到了hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.3.1</version>
</dependency>
  • 测试端口是否可达的工具类
import cn.hutool.core.util.NetUtil;
import javax.swing.*;
public class RabbitMQUtil {
public static void main(String[] args) {
checkServer();
}
public static void checkServer() {
//rabbitmq服务开启后默认端口为15672
if (NetUtil.isUsableLocalPort(15672)) {
JOptionPane.showMessageDialog(null, "RabbitMQ服务器未启动");
System.exit(1);
} else {
System.out.println("ActiveMQ服务器已启动");
}
}
}
  • 模式fanout广播,类似activemq的topic

创建一个producer和AB两个consumer,先运行两个consumer再运行producer,可以观察控制台情况:producer发送100个消息,AB两个consumer分别全部接收了这100个消息

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import message.rabbitmq.RabbitMQUtil;
public class FanoutProducer {
public final static String EXCHANGE_NAME = "fanout_exchange";
public static void main(String[] args) throws IOException, TimeoutException {
RabbitMQUtil.checkServer();
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置RabbitMQ相关信息
factory.setHost("localhost");
//创建一个新的连接
Connection connection = factory.newConnection();
//创建一个通道
Channel channel = connection.createChannel();
//设置消息类型
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
for (int i = 0; i < 100; i++) {
String message = "fanout消息:" + i;
//发送消息到队列中
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes(StandardCharsets.UTF_8));
System.out.println("Fanout发送消息:" + message);
}
//关闭通道和连接
channel.close();
connection.close();
}
}
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.*;
import cn.hutool.core.util.RandomUtil;
import message.rabbitmq.RabbitMQUtil;
public class FanoutCustomerA {
public final static String EXCHANGE_NAME = "fanout_exchange";
public static void main(String[] args) throws IOException, TimeoutException {
//为当前消费者取随机名
String name = "consumer-" + RandomUtil.randomString(5);
//判断服务器是否启动
RabbitMQUtil.checkServer();
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置RabbitMQ地址
factory.setHost("localhost");
//创建一个新的连接
Connection connection = factory.newConnection();
//创建一个通道
Channel channel = connection.createChannel();
//交换机声明-交换机名称+交换机类型
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
//获取一个临时队列
String queueName = channel.queueDeclare().getQueue();
//队列与交换机绑定-队列名称+交换机名称+routingKey忽略
channel.queueBind(queueName, EXCHANGE_NAME, "");
System.out.println(name + "FanoutConsumerA等待接受消息");
//监听指定频道消息
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, StandardCharsets.UTF_8);
System.out.println(name + "FanoutConsumerA接收到消息:" + message);
}
};
//自动回复队列应答 -- RabbitMQ中的消息确认机制
channel.basicConsume(queueName, true, consumer);
}
}
  • 模式2direct分食,类似activemq的queue

创建ABC三个consumer,运行后发现producer发送了100个消息,被ABC平均消费了,所以我理解为分食

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import message.rabbitmq.RabbitMQUtil;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
public class DirectProducer {
public static final String QUEUE_NAME = "direct_queue";
public static void main(String[] args) throws IOException, TimeoutException {
RabbitMQUtil.checkServer();
//创建ConnectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
//设置host
connectionFactory.setHost("localhost");
//创建连接
Connection connection = connectionFactory.newConnection();
//创建频道
Channel channel = connection.createChannel();
//设置消息类型
channel.exchangeDeclare(QUEUE_NAME, BuiltinExchangeType.TOPIC);
//发送消息
for (int i = 0; i < 50; i++) {
String message = "direct消息:" + i;
channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
System.out.println("DirectProducer发送消息:" + i);
}
//关闭连接
channel.close();
connection.close();
}
}
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
import cn.hutool.core.util.RandomUtil;
import message.rabbitmq.RabbitMQUtil;
public class DirectConsumerA {
private final static String QUEUE_NAME = "direct_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//为当前消费者取随机名
String name = "consumer-" + RandomUtil.randomString(5);
//判断服务器是否启动
RabbitMQUtil.checkServer();
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置RabbitMQ地址
factory.setHost("localhost");
//创建一个新的连接
Connection connection = factory.newConnection();
//创建一个通道
Channel channel = connection.createChannel();
//声明要关注的队列
channel.queueDeclare(QUEUE_NAME, false, false, true, null);
System.out.println(name + "->等待接受消息");
//监听平道
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, StandardCharsets.UTF_8);
System.out.println(name + "->接收到消息:" + message);
}
};
//自动回复队列应答 -- RabbitMQ中的消息确认机制
channel.basicConsume(QUEUE_NAME, true, consumer);
}
}
  • 模式topic主题订阅

比如发送消息:刘德华电影,刘德华歌曲,刘德华电视剧,如果订阅刘德华,则会收到三个消息,订阅了电影则只收到刘德华电影这个消息

import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import message.rabbitmq.RabbitMQUtil;
public class TopicProducer {
public final static String EXCHANGE_NAME = "topics_exchange";
public static void main(String[] args) throws IOException, TimeoutException {
RabbitMQUtil.checkServer();
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置RabbitMQ相关信息
factory.setHost("localhost");
//创建一个新的连接
Connection connection = factory.newConnection();
//创建一个通道
Channel channel = connection.createChannel();
//设置消息模式
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
String[] routing_keys = new String[]{"usa.news", "usa.weather", "europe.news", "europe.weather"};
String[] messages = new String[]{"美国新闻", "美国天气", "欧洲新闻", "欧洲天气"};
for (int i = 0; i < routing_keys.length; i++) {
String routingKey = routing_keys[i];
String message = messages[i];
channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes());
System.out.printf("TopicProducer发送消息到路由:%s, 内容是:%s%n", routingKey, message);
}
//关闭通道和连接
channel.close();
connection.close();
}
}
import com.rabbitmq.client.*;
import message.rabbitmq.RabbitMQUtil;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
public class TopicCustomer4USA {
public final static String EXCHANGE_NAME = "topics_exchange";
public static void main(String[] args) throws IOException, TimeoutException {
//为当前消费者取名称
String name = "consumer-usa";
//判断服务器是否启动
RabbitMQUtil.checkServer();
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//设置RabbitMQ地址
factory.setHost("localhost");
//创建一个新的连接
Connection connection = factory.newConnection();
//创建一个通道
Channel channel = connection.createChannel();
//交换机声明(参数为:交换机名称;交换机类型)
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
//获取一个临时队列
String queueName = channel.queueDeclare().getQueue();
//接受 USA 信息
channel.queueBind(queueName, EXCHANGE_NAME, "usa.*");
System.out.println(name + "->等待接受消息");
//监听消息
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, StandardCharsets.UTF_8);
System.out.println(name + "->接收到消息:" + message);
}
};
//自动回复队列应答 -- RabbitMQ中的消息确认机制
channel.basicConsume(queueName, true, consumer);
}
}
public class TopicCustomer4NEWS {
//...
channel.queueBind(queueName, EXCHANGE_NAME, "*.news");
//...
}