消息中间件rabbitmq主要有四种模式:fanout广播、direct分食、topic主题订阅、header-不常用,代码都很类似,主要区别是创建消息主题时会区别声明exchangeDeclare(),还有消息接收后需要给producer一个确认消息
环境准备
-
服务准备
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
-
rabbitmq服务开启
//用管理员权限使用命令行执行 net start RabbitMQ
-
服务启动截图
-
进入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"); //... }