這篇文章主要介紹下fanout類型的exchange。fanout,顧名思義,就是像風扇吹麪粉一樣,吹得到處都是。如果使用fanout類型的exchange,那麼routing key就不重要了。因爲我們向exchange發送消息時用不着指定routing key,它會把消息給每個綁定到該exchange的queue發一份。
package com.jaeger.exchange.fanout; import java.io.IOException; import java.util.concurrent.TimeoutException; import org.junit.Test; 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; public class Producer { private static final String MY_EXCHANGE_NAME = "MyExchange"; private static final String MY_ROUTING_KEY1 = "MyRoutingKey1"; private static final String MY_QUEUE_NAME1 = "MyQueue1"; private static final String MY_ROUTING_KEY2 = "MyRoutingKey2"; private static final String MY_QUEUE_NAME2 = "MyQueue2"; private static final String MY_ROUTING_KEY3 = "MyRoutingKey3"; private static final String MY_QUEUE_NAME3 = "MyQueue3"; private static final String FANOUT = "fanout"; private static final String HOST = "172.19.64.21"; private static final String USER = "jaeger"; private static final String PASSWORD = "root"; private static final int PORT = 5672; @Test public void createExchangeAndQueue() throws IOException, TimeoutException { ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.setHost(HOST); connectionFactory.setUsername(USER); connectionFactory.setPassword(PASSWORD); connectionFactory.setPort(PORT); Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); // 創建一個fanout類型的exchange channel.exchangeDeclare(MY_EXCHANGE_NAME, FANOUT); // 創建三個queue channel.queueDeclare(MY_QUEUE_NAME1, false, false, false, null); channel.queueDeclare(MY_QUEUE_NAME2, false, false, false, null); channel.queueDeclare(MY_QUEUE_NAME3, false, false, false, null); // 創建三個routing key,把exchange和queue綁定到一起 channel.queueBind(MY_QUEUE_NAME1, MY_EXCHANGE_NAME, MY_ROUTING_KEY1); channel.queueBind(MY_QUEUE_NAME2, MY_EXCHANGE_NAME, MY_ROUTING_KEY2); channel.queueBind(MY_QUEUE_NAME3, MY_EXCHANGE_NAME, MY_ROUTING_KEY3); channel.close(); connection.close(); } @Test public void produce() throws IOException, TimeoutException { ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.setHost(HOST); connectionFactory.setUsername(USER); connectionFactory.setPassword(PASSWORD); connectionFactory.setPort(PORT); Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); String message = "Hello 世界!"; /* 向RabbitMQ發送消息。我們這裏指定了exchange和routing key的名稱,RabbitMQ會去找有沒有叫這個名稱的exchange, 如果找到了又發現這個exchange是fanout類型,就不會再去看routing key了,而是把消息放到所有綁定到這個exchange的queue裏面。 這裏我們雖然指定了一個routing key,但實際上是沒有任何效果的,我們還可以用空字符串,最後消息都是到達所有queue的。 */ channel.basicPublish(MY_EXCHANGE_NAME, MY_ROUTING_KEY1, null, message.getBytes("utf-8")); //channel.basicPublish(MY_EXCHANGE_NAME, "", null, message.getBytes("utf-8")); System.out.println("Sent '" + message + "'"); channel.close(); connection.close(); } @Test public void consume() throws IOException, TimeoutException, InterruptedException{ ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.setHost(HOST); connectionFactory.setUsername(USER); connectionFactory.setPassword(PASSWORD); connectionFactory.setPort(PORT); Connection connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); 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, "UTF-8"); System.out.println("Received '" + message + "'"); } }; channel.basicConsume(MY_QUEUE_NAME1, true, consumer); Thread.sleep(1000); } }
我們先運行createExchangeAndQueue,把三個queue綁定到一個fanout類型的exchange上:
再運行produce方法,把消息發到exchange讓其轉發:
我們看到雖然我們指定了一個routing key,但實際上沒什麼用,也可以用""代替,消息會發到每一個queue裏面。
最後我們運行consume方法,讓它去消費MyQueue1隊列裏面的消息:
可以看到MyQueue1裏面的消息被消費掉了。