springboot:整合rabbitmq之交换机

本文详细介绍了如何在SpringBoot中整合RabbitMQ,讲解了不同类型的交换机,包括发布订阅、路由、主题和头部模式,并通过实例展示了它们的工作原理和配置。内容涵盖交换机配置、生产者、消费者以及消息处理过程。
摘要由CSDN通过智能技术生成

springboot:整合rabbitmq之交换机

环境准备

依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

配置

@Configuration
public class RabbitMQConfiguration {


    @Bean
    public ConnectionFactory rabbitConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        String rabbitmqHost = "127.0.0.1";
        String rabbitmqPort = "5672";
        String rabbitmqUsername = "guest";
        String rabbitmqPassword = "guest";
        String rabbitmqVirtualHost = "/";
        connectionFactory.setHost(rabbitmqHost);
        connectionFactory.setPort(Integer.parseInt(rabbitmqPort));
        connectionFactory.setUsername(rabbitmqUsername);
        connectionFactory.setPassword(rabbitmqPassword);
        connectionFactory.setVirtualHost(rabbitmqVirtualHost);
//        connectionFactory.setPublisherReturns(true);//开启return模式
//        connectionFactory.setPublisherConfirms(true);//开启confirm模式
        return connectionFactory;
    }


    @Bean(name = "rabbitTemplate")
    //必须是prototype类型
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public RabbitTemplate rabbitTemplate() {
        return new RabbitTemplate(rabbitConnectionFactory());
    }

    @Bean("customContainerFactory")
    public SimpleRabbitListenerContainerFactory containerFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        //设置线程数
        factory.setConcurrentConsumers(1);
        //最大线程数
        factory.setMaxConcurrentConsumers(1);
//        //设置为手动确认MANUAL(手动),AUTO(自动);
//        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        // 设置prefetch
        factory.setPrefetchCount(1);
        configurer.configure(factory, connectionFactory);
        return factory;
    }
}

一、交换机

生产者发送消息给交换机,由交换机转发消息给队列,交换机可以转发给所有绑定它的队列,也可以转发给符合路由规则的队列,交换机本身不会存储消息,如果没有绑定任何队列,消息就会丢失

  • 发布订阅模型
    发布订阅使用的交换机是Fanout交换机,也叫广播式交换机
    广播式交换机:fanout交换器中没有路由键的概念,他会把消息发送到所有绑定在此交换器上面的队列
  • 路由模型
    路由式交换机:direct交换器相对来说比较简单,匹配规则为:路由键完全匹配,消息就被投送到相关的队列
  • 主题模型
    主题式交换机:topic交换器采用模糊匹配路由键的原则进行转发消息到队列中
  • 头部订阅
    头部订阅(headers 交换机):headers没有路由键,是根据消息头部header的键值对进行匹配,可以完全匹配也可以匹配任意一对键值对

二、交换机模式

发布订阅

在这里插入图片描述

生产者生产10条消息,发送给FanoutExchange,空字符串""表示不需要指定路由键

消费者A监听队列A,消费者B、B2监听队列B

@RestController
public class FanoutExchangeController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/fanout")
    public void fanout() {
        for (int i = 1; i <= 10; i++) {
            String message = "Hello World ..." + i;
            rabbitTemplate.convertAndSend("fanout_exchange", "", message);
            System.out.println(" [ 生产者 ] Sent ==> '" + message + "'");
        }
    }

    private int count1 = 1;
    private int count2 = 1;
    private int count3 = 1;

    @RabbitListener(containerFactory = "customContainerFactory", bindings = {@QueueBinding(
            value = @Queue(value = "fanout_a", declare = "true"),
            exchange = @Exchange(value = "fanout_exchange", type = ExchangeTypes.FANOUT, durable = "true")
    )
    })
    public void receiveA(String message) throws InterruptedException {
        System.out.println(" [ 消费者@A号 ] Received ==> '" + message + "'");
        Thread.sleep(200);
        System.out.println(" [ 消费者@A号 ] Dealt with:" + count1++);
    }

    @RabbitListener(containerFactory = "customContainerFactory", bindings = {@QueueBinding(
            value = @Queue(value = "fanout_b", declare = "true"),
            exchange = @Exchange(value = "fanout_exchange", type = ExchangeTypes.FANOUT, durable = "true")
    )
    })
    public void receiveB(String message) throws InterruptedException {
        System.out.println(" [ 消费者@B号 ] Received ==> '" + message + "'");
        Thread.sleep(200);
        System.out.println(" [ 消费者@B号 ] Dealt with:" + count2++);
    }

    @RabbitListener(containerFactory = "customContainerFactory", bindings = {@QueueBinding(
            value = @Queue(value = "fanout_b", declare = "true"),
            exchange = @Exchange(value = "fanout_exchange", type = ExchangeTypes.FANOUT, durable = "true")
    )
    })
    public void receiveB2(String message) throws InterruptedException {
        System.out.println(" [ 消费者@B2号 ] Received ==> '" + message + "'");
        Thread.sleep(500);
        System.out.println(" [ 消费者@B2号 ] Dealt with:" + count3++);
    }
}

运行结果

生产者生产了10条消息发送给交换机,fanout交换机将消息分别转发给绑定它的队列A、B;
队列A、B拿到内容一样的10条消息,队列A只有一个消费者A,所以由消费者A处理所有消息
队列B有两个消费者B、B2,分配模式是按能力分配,所以消费者B处理的多

在这里插入图片描述

路由模式

在这里插入图片描述

@RestController
public class DirectController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private int count1 = 1;
    private int count2 = 1;
    private int count3 = 1;

    @GetMapping("/direct")
    public void direct() {
        for (int i = 1; i <= 30; i++) {
            String message = "Hello World ..." + i;
            System.out.println(" [ 生产者 ] Sent ==> '" + message + "'");
            if (i % 3 == 0) {
                rabbitTemplate.convertAndSend("direct_exchange", "direct_a", message);
            } else if (i % 3 == 1) {
                rabbitTemplate.convertAndSend("direct_exchange", "direct_b", message);
            } else {
                rabbitTemplate.convertAndSend("direct_exchange", "direct_b2", message);
            }
        }
    }

    /**
     * name:交换机名称
     * durable:设置是否持久,设置为true则将Exchange存盘,即使服务器重启数据也不会丢失
     * autoDelete:设置是否自动删除,当最后一个绑定到Exchange上的队列删除后,自动删除该Exchange,简单来说也就是如果该Exchange没有和任何队列Queue绑定则删除
     * internal:设置是否是RabbitMQ内部使用,默认false。如果设置为 true ,则表示是内置的交换器,客户端程序无法直接发送消息到这个交换器中,只能通过交换器路由到交换器这种方式。
     * @param message
     * @throws InterruptedException
     */
    @RabbitListener(containerFactory = "customContainerFactory", bindings = {@QueueBinding(
            value = @Queue(value = "direct_a", declare = "true"),
            exchange = @Exchange(value = "direct_exchange", type = ExchangeTypes.DIRECT, durable = "true"),
            key = "direct_a"
    )
    })
    public void receiveA(String message) throws InterruptedException {
        System.out.println(" [ 消费者@A号 ] Received ==> '" + message + "'");
        Thread.sleep(200);
        System.out.println(" [ 消费者@A号 ] Dealt with:" + count1++);
    }

    @RabbitListener(containerFactory = "customContainerFactory", bindings = {@QueueBinding(
            value = @Queue(value = "direct_b", declare = "true"),
            exchange = @Exchange(value = "direct_exchange", type = ExchangeTypes.DIRECT, durable = "true"),
            key = "direct_b"
    )
    })
    public void receiveB(String message) throws InterruptedException {
        System.out.println(" [ 消费者@B号 ] Received ==> '" + message + "'");
        Thread.sleep(200);
        System.out.println(" [ 消费者@B号 ] Dealt with:" + count2++);
    }

    @RabbitListener(containerFactory = "customContainerFactory", bindings = {@QueueBinding(
            value = @Queue(value = "direct_b", declare = "true"),
            exchange = @Exchange(value = "direct_exchange", type = ExchangeTypes.DIRECT, durable = "true"),
            key = "direct_b2"
    )
    })
    public void receiveB2(String message) throws InterruptedException {
        System.out.println(" [ 消费者@B2号 ] Received ==> '" + message + "'");
        Thread.sleep(500);
        System.out.println(" [ 消费者@B2号 ] Dealt with:" + count3++);
    }
}

运行结果

两个队列A、B,A有一个路由键,而B有两个路由键;
生产者生产30条消息发送给交换机,交换机根据路由键转发给队列,队列A分配10条消息,队列B分配20条消息;
同时队列D被两个消费者监听

在这里插入图片描述

主题模式(通配者模式)

@RestController
public class TopicController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private int count1 = 1;
    private int count2 = 1;
    private int count3 = 1;

    @GetMapping("/topic")
    public void topic() {
        for (int i = 1; i <= 30; i++) {
            String message = "Hello World ..." + i;
            System.out.println(" [ 生产者 ] Sent ==> '" + message + "'");
            if (i % 3 == 0) {
                // topic.yzm.key,可以匹配 topic.yzm.* 和 topic.#
                rabbitTemplate.convertAndSend("topic_exchange", "topic.yzm.key", message);
            } else if (i % 3 == 1) {
                // topic.yzm.yzm,可以匹配 topic.yzm.* 、 topic.# 和 topic.*.yzm
                rabbitTemplate.convertAndSend("topic_exchange", "topic.yzm.yzm", message);
            } else {
                // topic.key.yzm,可以匹配 topic.# 和 topic.*.yzm
                rabbitTemplate.convertAndSend("topic_exchange", "topic.key.yzm", message);
            }
        }
    }

    @RabbitListener(containerFactory = "customContainerFactory", bindings = {@QueueBinding(
            value = @Queue(value = "topic_e", declare = "true"),
            exchange = @Exchange(value = "topic_exchange", type = ExchangeTypes.TOPIC, durable = "true"),
            key = "topic.yzm.*"
    )
    })
    public void receiveE(String message) throws InterruptedException {
        System.out.println(" [ 消费者@E号 ] Received ==> '" + message + "'");
        Thread.sleep(200);
        System.out.println(" [ 消费者@E号 ] Dealt with:" + count1++);
    }

    @RabbitListener(containerFactory = "customContainerFactory", bindings = {@QueueBinding(
            value = @Queue(value = "topic_f", declare = "true"),
            exchange = @Exchange(value = "topic_exchange", type = ExchangeTypes.TOPIC, durable = "true"),
            key = "topic.#"
    )
    })
    public void receiveF(String message) throws InterruptedException {
        System.out.println(" [ 消费者@F号 ] Received ==> '" + message + "'");
        Thread.sleep(200);
        System.out.println(" [ 消费者@F号 ] Dealt with:" + count2++);
    }

    @RabbitListener(containerFactory = "customContainerFactory", bindings = {@QueueBinding(
            value = @Queue(value = "topic_g", declare = "true"),
            exchange = @Exchange(value = "topic_exchange", type = ExchangeTypes.TOPIC, durable = "true"),
            key = "topic.*.yzm"
    )
    })
    public void receiveG(String message) throws InterruptedException {
        System.out.println(" [ 消费者@G号 ] Received ==> '" + message + "'");
        Thread.sleep(200);
        System.out.println(" [ 消费者@G号 ] Dealt with:" + count3++);
    }
}

分析结果:

E、G二十条,F三十条

在这里插入图片描述

头部模式

配置类

@Configuration
public class RabbitMQConfiguration {


    @Bean
    public ConnectionFactory rabbitConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        String rabbitmqHost = "127.0.0.1";
        String rabbitmqPort = "5672";
        String rabbitmqUsername = "guest";
        String rabbitmqPassword = "guest";
        String rabbitmqVirtualHost = "/";
        connectionFactory.setHost(rabbitmqHost);
        connectionFactory.setPort(Integer.parseInt(rabbitmqPort));
        connectionFactory.setUsername(rabbitmqUsername);
        connectionFactory.setPassword(rabbitmqPassword);
        connectionFactory.setVirtualHost(rabbitmqVirtualHost);
//        connectionFactory.setPublisherReturns(true);//开启return模式
//        connectionFactory.setPublisherConfirms(true);//开启confirm模式
        return connectionFactory;
    }


    @Bean(name = "rabbitTemplate")
    //必须是prototype类型
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public RabbitTemplate rabbitTemplate() {
        return new RabbitTemplate(rabbitConnectionFactory());
    }

    @Bean("customContainerFactory")
    public SimpleRabbitListenerContainerFactory containerFactory(SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        //设置线程数
        factory.setConcurrentConsumers(1);
        //最大线程数
        factory.setMaxConcurrentConsumers(1);
//        //设置为手动确认MANUAL(手动),AUTO(自动);
//        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        // 设置prefetch
        factory.setPrefetchCount(1);
        configurer.configure(factory, connectionFactory);
        return factory;
    }

    public static final String QUEUE_X = "headers_x";
    public static final String QUEUE_Y = "headers_y";
    public static final String HEADER_EXCHANGE = "headers_exchange";

    @Bean
    public Queue queueX() {
        return new Queue(QUEUE_X);
    }

    @Bean
    public Queue queueY() {
        return new Queue(QUEUE_Y);
    }

    @Bean
    public HeadersExchange headersExchange() {
        return ExchangeBuilder.headersExchange(HEADER_EXCHANGE).build();
    }

    @Bean
    public Binding bindingX() {
        Map<String, Object> map = new HashMap<>();
        map.put("key1", "value1");
        map.put("name", "yzm");
        // whereAll:表示完全匹配
        return BindingBuilder.bind(queueX()).to(headersExchange()).whereAll(map).match();
    }

    @Bean
    public Binding bindingY() {
        Map<String, Object> map = new HashMap<>();
        map.put("key2", "value2");
        map.put("name", "yzm");
        // whereAny:表示只要有一对键值对能匹配就可以
        return BindingBuilder.bind(queueY()).to(headersExchange()).whereAny(map).match();
    }
}

消息发送和接受

@RestController
public class HeadersController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/headers")
    public void headers() {
        String s = "Hello World";
        System.out.println(" [ 生产者 ] Sent ==> '" + s + "'");
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setHeader("key1", "value1");
        messageProperties.setHeader("name", "yzm");
        Message message = new Message(s.getBytes(StandardCharsets.UTF_8), messageProperties);
        rabbitTemplate.convertAndSend("headers_exchange", "", message);
    }

    @GetMapping("/headers2")
    public void headers2() {
        String s = "Hello World";
        System.out.println(" [ 生产者 ] Sent ==> '" + s + "'");
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setHeader("key3", "value3");
        messageProperties.setHeader("name", "yzm");
        Message message = new Message(s.getBytes(StandardCharsets.UTF_8), messageProperties);
        rabbitTemplate.convertAndSend("headers_exchange", "", message);
    }

    @RabbitListener(queues = RabbitMQConfiguration.QUEUE_X)
    public void receiveX(String message) {
        System.out.println(" [ 消费者@X号 ] Received ==> '" + message + "'");
    }

    @RabbitListener(queues = RabbitMQConfiguration.QUEUE_Y)
    public void receiveY(String message) {
        System.out.println(" [ 消费者@Y号 ] Received ==> '" + message + "'");
    }
}

测试结果

发送请求:http://localhost:8080/headers

生产消息时,头部键值对有:“key1”=“value1"和"name”=“yzm”,跟X队列能完全匹配上,跟Y队列能匹配上其中一个,所以两个消费者都能消费到消息

在这里插入图片描述

发送请求:http://localhost:8080/headers2

只有Y队列能匹配上一个键值对

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Spring Boot项目中整合RabbitMQ,需要进行以下步骤: 1. 添加RabbitMQ依赖 在项目的pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> ``` 2. 配置RabbitMQ 在application.properties文件中添加以下配置: ``` spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=guest ``` 3. 创建消息发送者 在Spring Boot项目中,可以使用RabbitTemplate来发送消息。可以在类中注入RabbitTemplate: ``` @Autowired private RabbitTemplate rabbitTemplate; ``` 然后,在需要发送消息的方法中,可以使用rabbitTemplate.convertAndSend方法来发送消息: ``` rabbitTemplate.convertAndSend(exchangeName, routingKey, message); ``` 其中,exchangeName是交换机的名称,routingKey是路由键,message是要发送的消息。 4. 创建消息接收者 在Spring Boot项目中,可以使用@RabbitListener注解来创建消息接收者。可以在方法上添加@RabbitListener注解,并指定要监听的队列名称: ``` @RabbitListener(queues = "myqueue") public void receiveMessage(String message) { System.out.println("Received message: " + message); } ``` 当有消息到达指定的队列时,receiveMessage方法将被调用,并传入接收到的消息。 5. 运行应用程序 运行Spring Boot应用程序,并发送和接收RabbitMQ消息。 以上是在Spring Boot项目中整合RabbitMQ的基本步骤。根据具体的需求,可能需要进行更多的配置和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值