RabbiteMQ的Fanout模式其实和ActiveMQ的Topic模式比较类似,这里我们就来看一下见到的小例子吧,首先我们看生成者,这里生产者和RabbitMQ的基础使用 —— Direct模式(一)、RabbitMQ的基础使用 —— Direct模式(二)中的类似,其中最重要的就是需要将交换器的类型修改为Fanout
,如下:
public class FanoutProducer {
//交换器名称
public static final String EXCHANGE_NAME = "logs";
public static void main(String[] args) throws Exception {
//创建连接,连接到RabbitMQ
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection connection = connectionFactory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//创建交换器
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
//定义的业务日志消息级别,即作为路由键使用
String[] logLevels = {"error", "warn", "info"};
for (int i = 0; i < logLevels.length; i++) {
String logLevel = logLevels[i];
String msg = "Hello RabbitMQ";
//发布消息,需要参数:交换器、路由键,其中以日志消息级别为路由键
channel.basicPublish(EXCHANGE_NAME, logLevel, null, msg.getBytes(Charset.forName("UTF-8")));
}
channel.close();
connection.close();
}
}
然后我们再来看看消费者端,这里我们就用两个消费者来进行测试,一个消费者绑定路由键error
,另一个消费者这绑定一个不存在的路由键other
,如下:
public class ErrorConsumer {
public static final String EXCHANGE_NAME = "logs";
public static void main(String[] args) throws Exception {
//创建连接,连接到RabbitMQ,与发送端一样
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection connection = connectionFactory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//可不创建,由生产者进行创建
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
String queueName = "logError"; //声明一个队列名称
String routingKey = "error"; //路由键名称
//创建一个队列
channel.queueDeclare(queueName, false, false, false, null);
//将队列和交换器通过路由键进行绑定
channel.queueBind(queueName, EXCHANGE_NAME, routingKey);
//声明了一个消费者
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
StringBuffer buffer = new StringBuffer();
buffer.append(Thread.currentThread().getName()).append(", ")
.append(envelope.getExchange()).append(", ")
.append(envelope.getRoutingKey()).append(", ")
.append(new String(body, "UTF-8"));
System.out.println(buffer.toString());
}
};
//消费者正式开始在指定队列上消费消息
channel.basicConsume(queueName, true, consumer);
}
}
public class OtherConsumer {
public static final String EXCHANGE_NAME = "logs";
public static void main(String[] args) throws Exception {
//创建连接,连接到RabbitMQ,与发送端一样
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection connection = connectionFactory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//可不创建,由生产者进行创建
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
String queueName = "logOther"; //声明一个队列名称
String routingKey = "other"; //路由键名称
//创建一个队列
channel.queueDeclare(queueName, false, false, false, null);
//将队列和交换器通过路由键进行绑定
channel.queueBind(queueName, EXCHANGE_NAME, routingKey);
//声明了一个消费者
Consumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
StringBuffer buffer = new StringBuffer();
buffer.append(Thread.currentThread().getName()).append(", ")
.append(envelope.getExchange()).append(", ")
.append(envelope.getRoutingKey()).append(", ")
.append(new String(body, "UTF-8"));
System.out.println(buffer.toString());
}
};
//消费者正式开始在指定队列上消费消息
channel.basicConsume(queueName, true, consumer);
}
}
按我们预期的效果来看,应该不管我们如何调整生产者和消费者的路由键,都对消息的接受没有影响。下面我们进行测试,如下: