消息队列rabbitmq(三)rabbitmq概念以及rabbitmq整合springboot实现消息发送和接收的四种调度策略

一、rabbitmq概念

rabbitmq是消息中间件的一种,消息中间件就是分布式系统中完成消息的接收和发送基础软件

消息中间件的工作过程可以用生产者消费者模型来表示,即生产者不断向消息队列发送消息,而消费者从消息队列中消费信息。

rabbitmq除了生产者、消息队列、消费者这三个基本模块以外,还添加了一个模块,即交换机,交换机的存在使得生产者和消息队列产生了隔离,也就是生产者不是直接把消息发送给消息队列,而是生产者把消息先发送到交换机,交换机根据调度策略把消息发送给对应的消息队列。

交换机:交换机的主要作用是接收相应的消息并且绑定到指定的队列,交换机的类型有四种,我的理解是交换机的调度策略有四种,分别是Direct、topic、headers、Fanout。

Direct是rabbitmq默认的交换机模式,消息队列创建时就会被指定一个BindingKey,当发送者发送消息的时候,需要指定对应的Key,当key和消息队列的BingingKey一致的时候,消息就会发送到该消息队列中(类似于精确查询)。

topic:消息队列和交换机依据一种模式(通配符+字符串)互相绑定,当发送者发送消息时,只有指定的Key和该模式想匹配的时候,消息才会被发送到该消息队列中。(类似于模糊查询,关键字为key)

headers:消息队列和交换机依据一组键值对规则互相绑定,发送者发送消息的时候指定一组键值对规则,当两组键值对规则相匹配时,消息会被发送到匹配的消息队列中。

Fanout:是路由广播的形式,该类型交换机将会把发送者发来的消息发送给所有绑定它的全部队列,即使设置了key,也会被忽略,该消息不会只发送给指定的key的消息队列,而是会发送到所有绑定该交换机的消息队列。

 

二、springboot整合rabbitmq实现四种调度策略发送与接收消息

 

a.pom.xml

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

 application.properties配置文件

spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

 

为了模拟的是分布式系统,我建立了两个springboot项目,也可以在一个项目里建立两个maven模块代码

两个项目分别是 

 

一、direct交换机

 rabbitmq_sender发送端的代码:

由于采用的是Direct模式,需要在配置Queue的时候,指定一个键,使其和交换机绑定.

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SenderConf {
    @Bean
    public Queue queue() {
        return new Queue("queue");
    }
}

 接着就可以发送消息啦!在SpringBoot中,我们使用AmqpTemplate去发送消息!代码如下:

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HelloSender {
    @Autowired
    private AmqpTemplate template;

    public void send() {
        template.convertAndSend("queue", "hello,rabbit666~");
    }
}

 编写测试类!这样我们的发送端代码就编写完了~

import com.example.rabbitmq_sender.direct.HelloSender;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitmqSenderApplicationTests {
    @Autowired
    private HelloSender helloSender;

    @Test
    public void testRabbit() {
        helloSender.send();
    }
    @Test
    public void contextLoads() {
    }

}

 rabbitmq_receiver接收端代码

主要在于我们需要配置监听器去监听绑定到的消息队列,当消息队列有消息的时候,予以接收,代码如下:

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class HelloReceive {

    @RabbitListener(queues = "queue")    //监听器监听指定的Queue
    public void processC(String str) {
        System.out.println("Receive:" + str);
    }
}

 

接下来就可以测试啦,首先启动接收端的应用,紧接着运行发送端的单元测试,接收端应用打印出来接收到的消息,测试即成功!

需要注意的地方,Direct模式相当于一对一模式,一个消息被发送者发送后,会被转发到一个绑定的消息队列中,然后被一个接收者接收!

测试结果:

 

二、topic交换机

 首先我们看发送端,我们需要配置队列Queue,再配置交换机(Exchange),再把队列按照相应的规则绑定到交换机上:接收端也要进行该配置

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SenderConf1 {

    @Bean(name="message")
    public Queue queueMessage() {
        return new Queue("topic.message");
    }

    @Bean(name="messages")
    public Queue queueMessages() {
        return new Queue("topic.messages");
    }

    @Bean
    public TopicExchange exchange() {
        return new TopicExchange("exchange");
    }
    @Bean
    Binding bindingExchangeMessage(@Qualifier("message") Queue queueMessage, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
    }

    @Bean
    Binding bindingExchangeMessages(@Qualifier("messages") Queue queueMessages, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");//*表示一个词,#表示零个或多个词
    }
}

而在接收端,我们配置两个监听器,分别监听不同的队列:

 @RabbitListener(queues="topic.message")    //监听器监听指定的Queue
   public void process1(String str) {
    System.out.println("message:"+str);
    }
    @RabbitListener(queues="topic.messages")    //监听器监听指定的Queue
    public void process2(String str) {
        System.out.println("messages:"+str);
    }

 好啦!接着我们可以进行测试了!首先我们发送如下内容:

 public void sendTopic()
    {
        template.convertAndSend("exchange","topic.message","hello,rabbit~~~11");
        template.convertAndSend("exchange","topic.messages","hello,rabbit~~~22");
    }

消息队列有两个,一个是 topic.message,一个是topic.messages,当执行这两行代码时

A:template.convertAndSend("exchange","topic.message","hello,rabbit~~~11");
       

B:template.convertAndSend("exchange","topic.messages","hello,rabbit~~~22");
A这行代码所发送的第二个参数与topic.message和topic.messages这两个消息队列的模式都匹配,因此,第三个参数即","hello,rabbit~~~11"这个消息将会被发送到这两个消息队列中。

B这行代码所发送的第二个参数与topic.messages这个消息队列的模式匹配,因此,该消息将会被发送到该消息队列中去,即hello,rabbit~~~22这个消息将被发送到topic.messages这个消息队列中。

到目前为止,topic.messages消息队列有的消息为

  topic.message消息队列有的消息是

因此在接收端

 

 该监听器所获取的数据为

 

该监听器所获取的数据为:

 

 

 

 运行结果是:

 方法的第一个参数是交换机名称,第二个参数是发送的key,第三个参数是内容,RabbitMQ将会根据第二个参数去寻找有没有匹配此规则的队列,如果有,则把消息给它,如果有不止一个,则把消息分发给匹配的队列(每个队列都有消息!),显然在我们的测试中,参数2匹配了两个队列,因此消息将会被发放到这两个队列中,而监听这两个队列的监听器都将收到消息!那么如果把参数2改为topic.messages呢?显然只会匹配到一个队列,那么process2方法对应的监听器收到消息!

三、Fanout Exchange形式

Fanout Exchange形式又叫广播形式,因此我们发送到路由器的消息会使得绑定到该路由器的每一个Queue接收到消息,这个时候就算指定了Key,或者规则(即上文中convertAndSend方法的参数2),也会被忽略!那么直接上代码,发送端配置如下:

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SenderConf2 {

    @Bean(name="Amessage")
    public Queue AMessage() {
        return new Queue("fanout.A");
    }

    @Bean(name="Bmessage")
    public Queue BMessage() {
        return new Queue("fanout.B");
    }

    @Bean(name="Cmessage")
    public Queue CMessage() {
        return new Queue("fanout.C");
    }

    @Bean
    FanoutExchange fanoutExchange() {
        return new FanoutExchange("fanoutExchange");//配置广播路由器
    }

    @Bean
    Binding bindingExchangeA(@Qualifier("Amessage") Queue AMessage, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(AMessage).to(fanoutExchange);
    }

    @Bean
    Binding bindingExchangeB(@Qualifier("Bmessage") Queue BMessage, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(BMessage).to(fanoutExchange);
    }

    @Bean
    Binding bindingExchangeC(@Qualifier("Cmessage") Queue CMessage, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(CMessage).to(fanoutExchange);
    }

}

 发送端使用如下代码发送:

template.convertAndSend("fanoutExchange","","xixi,haha");//参数2忽略

 接收端监听器配置如下:

 @RabbitListener(queues="fanout.A")
    public void processA(String str1) {
        System.out.println("ReceiveA:"+str1);
    }
    @RabbitListener(queues="fanout.B")
    public void processB(String str) {
        System.out.println("ReceiveB:"+str);
    }
    @RabbitListener(queues="fanout.C")
    public void processC(String str) {
        System.out.println("ReceiveC:"+str);
    }

 运行测试代码,发现三个监听器都接收到了数据,测试成功!

运行结果:

本文参考来自: https://www.cnblogs.com/linyufeng/p/9885645.html

代码在码云上:https://gitee.com/fancyshu/rabbitmq

码云代码拉取下来不能直接用,需要分开成两个项目,单独运行就可以了 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值