exchange有以下四种类型:

  • direct
  • fanout
  • topic
  • headers

见枚举类com.rabbitmq.client.BuiltinExchangeType

public enum BuiltinExchangeType {

    DIRECT("direct"), FANOUT("fanout"), TOPIC("topic"), HEADERS("headers");
... ...

fanout

消息广播到绑定的队列,不管队列绑定了什么路由键,消息经过交换器,每个队列都有一份。

rabbitmq中exchange交换机的四种类型_消息中间件

FanoutProducer

package com.morris.rabbit.exchange.fanout;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;
import java.util.stream.IntStream;

public class FanoutProducer {

    public final static String EXCHANGE_NAME = "fanout-exchange";

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {

            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
            String message = "task";

            channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
            System.out.println(" [x] Sent '" + message + "'");
        }
    }
}

FanoutConsumer

package com.morris.rabbit.exchange.fanout;

import com.rabbitmq.client.*;

import static com.morris.rabbit.exchange.fanout.FanoutProducer.EXCHANGE_NAME;

public class FanoutConsumer {

    private final static String QUEUE_NAME = "fanout-queue";

    public static void main(String[] argv) throws Exception {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "*");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
    }
}

FanoutConsumer2

package com.morris.rabbit.exchange.fanout;

import com.rabbitmq.client.*;

import static com.morris.rabbit.exchange.fanout.FanoutProducer.EXCHANGE_NAME;

public class FanoutConsumer2 {

    private final static String QUEUE_NAME = "fanout-queue2";

    public static void main(String[] argv) throws Exception {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        channel.queueBind(QUEUE_NAME, FanoutProducer.EXCHANGE_NAME, "*");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
    }
}

测试

先运行FanoutConsumer和FanoutConsumer2,再运行FanoutProducer。

运行结果如下:

FanoutProducer:

[x] Sent 'task'

FanoutConsumer:

[*] Waiting for messages. To exit press CTRL+C
 [x] Received 'task'

FanoutConsumer2:

[*] Waiting for messages. To exit press CTRL+C
 [x] Received 'task'

direct

路由键完全匹配,消息被投递到对应的队列,direct交换器是默认交换器。声明一个队列时,会自动绑定到默认交换器,并且以队列名称作为路由
键。

rabbitmq中exchange交换机的四种类型_交换机_02

DirectProducer

package com.morris.rabbit.exchange.direct;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class DirectProducer {

    public final static String EXCHANGE_NAME = "direct-exchange";

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {
            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);

            channel.basicPublish(EXCHANGE_NAME, "c1", null, "task1".getBytes());
            System.out.println(" [x] Sent 'task1'");

            channel.basicPublish(EXCHANGE_NAME, "c2", null, "task2".getBytes());
            System.out.println(" [x] Sent 'task2'");
        }
    }
}

DirectConsumer

package com.morris.rabbit.exchange.direct;

import com.rabbitmq.client.*;

import static com.morris.rabbit.exchange.direct.DirectProducer.EXCHANGE_NAME;

public class DirectConsumer {

    private final static String QUEUE_NAME = "direct-queue";

    public static void main(String[] argv) throws Exception {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "c1");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
    }
}

DirectConsumer2

package com.morris.rabbit.exchange.direct;

import com.rabbitmq.client.*;

import static com.morris.rabbit.exchange.direct.DirectProducer.EXCHANGE_NAME;

public class DirectConsumer2 {

    private final static String QUEUE_NAME = "direct-queue2";

    public static void main(String[] argv) throws Exception {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        channel.queueBind(QUEUE_NAME, DirectProducer.EXCHANGE_NAME, "c2");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
    }
}

测试

先运行DirectConsumer和DirectConsumer2 ,再运行DirectProducer。

运行结果如下:

DirectProducer:

[x] Sent 'task1'
 [x] Sent 'task2'

DirectConsumer:

[*] Waiting for messages. To exit press CTRL+C
 [x] Received 'task1'

DirectConsumer2:

[*] Waiting for messages. To exit press CTRL+C
 [x] Received 'task2'

topic

通过使用“”和“#”通配符进行处理,使来自不同源头的消息到达同一个队列,”.”将路由键分为了几个标识符,“”匹配 1 个,“#”匹配一个

或多个。

rabbitmq中exchange交换机的四种类型_消息中间件_03

TopicProducer

package com.morris.rabbit.exchange.topic;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class TopicProducer {

    public final static String EXCHANGE_NAME = "topic-exchange";

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {
            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);

            channel.basicPublish(EXCHANGE_NAME, "xxx.aaa", null, "task1".getBytes());
            System.out.println(" [x] Sent 'task1'");

            channel.basicPublish(EXCHANGE_NAME, "xxx.bbb", null, "task2".getBytes());
            System.out.println(" [x] Sent 'task2'");
        }
    }
}

TopicConsumer

package com.morris.rabbit.exchange.topic;

import com.rabbitmq.client.*;

import static com.morris.rabbit.exchange.topic.TopicProducer.EXCHANGE_NAME;

public class TopicConsumer {

    private final static String QUEUE_NAME = "topic-queue";

    public static void main(String[] argv) throws Exception {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "xxx.#");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
    }
}

TopicConsumer2

package com.morris.rabbit.exchange.topic;

import com.rabbitmq.client.*;

import static com.morris.rabbit.exchange.topic.TopicProducer.EXCHANGE_NAME;

public class TopicConsumer2 {

    private final static String QUEUE_NAME = "topic-queue2";

    public static void main(String[] argv) throws Exception {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        channel.queueBind(QUEUE_NAME, TopicProducer.EXCHANGE_NAME, "#.bbb");
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
    }
}

测试

先运行TopicConsumer和TopicConsumer2 ,再运行TopicProducer 。

运行结果如下:

TopicProducer :

[x] Sent 'task1'
 [x] Sent 'task2'

TopicConsumer:

[*] Waiting for messages. To exit press CTRL+C
 [x] Received 'task1'
 [x] Received 'task2'

TopicConsumer2:

[*] Waiting for messages. To exit press CTRL+C
 [x] Received 'task2'

headers

header exchange和direct exchange有点相似,但是不同于direct exchange的路由是基于路由键,header exchange的路由值基于消息的header数据。

HeaderProducer

package com.morris.rabbit.exchange.header;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;

public class HeaderProducer {

    public final static String EXCHANGE_NAME = "header-exchange";

    public static void main(String[] args) throws IOException, TimeoutException {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        try (Connection connection = factory.newConnection();
             Channel channel = connection.createChannel()) {
            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.HEADERS);

            Map<String,Object> headersMap  = new HashMap<>();
            headersMap.put("api-version", "5.1.0");
            headersMap.put("platform", "android");
            AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
            AMQP.BasicProperties properties = builder.headers(headersMap).build();
            channel.basicPublish(EXCHANGE_NAME, "", properties, "task1".getBytes());
            System.out.println(" [x] Sent 'task1'");

            headersMap.put("api-version", "5.2.0");
            headersMap.put("platform", "android");
            properties = builder.headers(headersMap).build();
            channel.basicPublish(EXCHANGE_NAME, "", properties, "task2".getBytes());
            System.out.println(" [x] Sent 'task2'");

        }
    }
}

HeaderConsumer

package com.morris.rabbit.exchange.header;

import com.rabbitmq.client.*;

import java.util.HashMap;
import java.util.Map;

import static com.morris.rabbit.exchange.header.HeaderProducer.EXCHANGE_NAME;

public class HeaderConsumer {

    private final static String QUEUE_NAME = "header-queue";

    public static void main(String[] argv) throws Exception {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.HEADERS);
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        Map<String,Object> headersMap  = new HashMap<>();
        headersMap.put("api-version", "5.1.0");
        headersMap.put("platform", "android");
        headersMap.put("x-match","all"); // 全匹配
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "", headersMap);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
    }
}

HeaderConsumer2

package com.morris.rabbit.exchange.header;

import com.rabbitmq.client.*;

import java.util.HashMap;
import java.util.Map;

import static com.morris.rabbit.exchange.header.HeaderProducer.EXCHANGE_NAME;

public class HeaderConsumer2 {

    private final static String QUEUE_NAME = "header-queue2";

    public static void main(String[] argv) throws Exception {

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.80.205");
        factory.setPort(5672);
        factory.setUsername("root");
        factory.setPassword("root");
        Connection connection = factory.newConnection();
        Channel channel = connection.createChannel();
        channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.HEADERS);
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        Map<String,Object> headersMap  = new HashMap<>();
        headersMap.put("api-version", "5.1.0");
        headersMap.put("platform", "android");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "", headersMap);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {});
    }
}

测试

先运行HeaderConsumer和HeaderConsumer2 ,再运行HeaderProducer 。

运行结果如下:

HeaderProducer :

[x] Sent 'task1'
 [x] Sent 'task2'

HeaderConsumer:

[*] Waiting for messages. To exit press CTRL+C
 [x] Received 'task1'

HeaderConsumer2:

[*] Waiting for messages. To exit press CTRL+C
 [x] Received 'task1'
 [x] Received 'task2'

消息header数据里有一个特殊值x-match,它有两个值:

  • all:一个传送消息的header里的键值对和交换机的header键值对全部匹配,才可以路由到对应交换机
  • any:默认值。一个传送消息的header里的键值对和交换机的header键值对任意一个匹配,就可以路由到对应交换机