RabbitMQ六种模式

22 篇文章 0 订阅
9 篇文章 0 订阅

前言

以下代码在我github里也有https://github.com/Codeouter/Example/tree/test/Project/rabbit-modes

一、配置

xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>rabbit-modes</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.1.4.RELEASE</version>
    </parent>

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

yml文件如下,每个model的ym配置基本一致所以就写这一个算了。

server:
  port: 8080   #这个端口看自己喜好
spring:
  application:
    name: provider-mode1
  rabbitmq:
    port: 5673       #这个端口看自己的配置,默认是5672
    host: 192.168.136.128  #我这是自己的虚拟机上的,如果不是用虚拟机的就localhost
    username: admin			#账号密码看自己设置
    password: admin

一、Hello World

这种方式是最简单的方式,生产者直接将消息投递到队列里,消费者直接监听队列消费消息
在这里插入图片描述

1.生产者

首先写个配置类,其实就是创建个队列

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

@Configuration
public class Config {

    @Bean
    public Queue myQueue(){
        return new Queue("myQueue");
    }
}

然后写个发送的逻辑

mport org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Component
public class Sender {
    @Autowired
    RabbitTemplate rabbitTemplate;

    public void send(){
        String messageData = "test message, hello!";
        String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        Map<String,Object> map=new HashMap<>();
        map.put("messageData",messageData);
        map.put("createTime",createTime);
        rabbitTemplate.convertAndSend("myQueue", map);
    }
}

其实这里有个小细节,当我们在IDE里打出rabbitTemplate.convertAndSend的时候,会有如下这些重载的方法
在这里插入图片描述没有哪个方法是说发送到某个队列里的,而是交换器或者是路由键。而我们用的显然是第一个,也就是说在此情况下,队列名字就充当了路由键。

最后是一个Controller

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SendController {
    @Autowired
    Sender sender;
    @GetMapping("/send")
    public String send(){
        sender.send();
        return "ok";
    }
}

启动类就不多说了,自己写吧

2.消费者

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;

@Component
@RabbitListener(queues = "myQueue")
public class Consumer {
    @RabbitHandler
    public void receive(Map msg){
        String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println("receive: " + msg.toString() + "current time is:" + nowTime);
    }
}

最后会得到如下结果
在这里插入图片描述

二、Work Queues

这种就是一个生产者多个消费者
在这里插入图片描述这个单生产者与多生产者基本相似,我们只展示不太相同的部分。

1.生产者

public class Sender {
    @Autowired
    RabbitTemplate rabbitTemplate;

    public void send(int curId){
        String messageData = "test message, hello!";
        String currentId = "curId";
        String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        Map<String,Object> map=new HashMap<>();
        map.put(currentId, curId);
        map.put("messageData",messageData);
        map.put("createTime",createTime);
        rabbitTemplate.convertAndSend("myQueue", map);
    }
}

为了能够更好的观看竞争状况,对send函数修改一下能够加入Id去看哪个消息被哪个消费者接收。
下面就是对controller小小的修改

@RestController
public class SendController {
    @Autowired
    Sender sender;
    @GetMapping("/send")
    public String send(){
        for(int i = 0; i < 50; i++){
            sender.send(i); //每个消息都加入一个id标识一下
        }
        return "ok";

    }
}

2.消费者

@Component
@RabbitListener(queues = "myQueue")
public class Consumer {
    @RabbitHandler
    public void receive(Map msg){
        String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println("### Conusumer1 ### receive: " + msg.toString() + "current time is:" + nowTime);
    }
}

@Component
@RabbitListener(queues = "myQueue")
public class Consumer1 {
    @RabbitHandler
    public void receive(Map msg){
        String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println("### Conusumer2 ### receive: " + msg.toString() + "current time is:" + nowTime);
    }
}

最终产生的结果大概就是这样。
在这里插入图片描述

三、Publish/Subscribe

在这里插入图片描述这种情况是生产者先发给一个交换器,然后交换器再发送给队列,而消费者则是监听队列获取消息。
这个与上边的work queues非常相似,区别是本模式同一个消息可以被多次消费,而work queues智能消费一次

由于后边要进行路由之类的所以到此时,我们使用yml进行配置队列名以及交换机名

server:
  port: 8084
spring:
  application:
    name: provider-mode-workqueue
  rabbitmq:
    port: 5673
    host: 192.168.136.128
    username: admin
    password: admin
my:
  provider:
    queue1: myQueue1
    exchange: myExchange
    queue2: myQueue2

1.生产者

对于上面publish模式,与上边的不同只是在配置类上面,这次需要创建两个队列,并且还有交换机,以及它们之间的绑定。

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.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

@Configuration
public class Config {
    @Autowired
    private Environment env;

    @Bean
    public Queue myQueue(){

        return new Queue(env.getProperty("my.provider.queue1"));
    }
    @Bean
    Queue myQueue1(){
        return new Queue(env.getProperty("my.provider.queue2"));
    }

    @Bean
    public FanoutExchange myExchange(){
        return new FanoutExchange(env.getProperty("my.provider.exchange"));
    }

    @Bean
    Binding bindingQueue1(){
        return BindingBuilder.bind(myQueue())
                .to(myExchange());
    }
    @Bean
    Binding bindingQueue2(){
        return BindingBuilder.bind(myQueue1())
                .to(myExchange());
    }
}

发送的逻辑与之前的几乎没有差别,差别局势发送时要指定交换机。

@Component
public class Sender {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    private Environment env;

    public void send(int curId){
        String messageData = "test message, hello!";
        String currentId = "curId";
        String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        Map<String,Object> map=new HashMap<>();
        map.put(currentId, curId);
        map.put("messageData",messageData);
        map.put("createTime",createTime);
        rabbitTemplate.convertAndSend(env.getProperty("my.provider.exchange"),"", map);

    }

}

2.消费者

@Component
@RabbitListener(queues = "myQueue1")
public class Consumer {
    @RabbitHandler
    public void receive(Map msg){
        String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println("### Conusumer1 ### receive: " + msg.toString() + "current time is:" + nowTime);
    }
}

@Component
@RabbitListener(queues = "myQueue2")
public class Consumer1 {
    @RabbitHandler
    public void receive(Map msg){
        String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        System.out.println("### Conusumer2 ### receive: " + msg.toString() + "current time is:" + nowTime);
    }
}

结果如下
在这里插入图片描述

四、路由模式

需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配,
在这里插入图片描述这个代码就不贴了,之前我写的有篇文章就是这样https://blog.csdn.net/smy166153/article/details/117456651?spm=1001.2014.3001.5502,同时下面的主题模式也几乎一致。

五、主题模式

同样是将bindingkey和routingkey绑定,但是规则有些不同。
它约定:

RoutingKey为由"."分割的字符串,如com.rabbitmq.client
BindingKey同样如此
BindingKey可以存在两种不同的字符,“*"和”#“ 其中 * 用于匹配一个单词,#用于匹配多个单词
headers
headers的交换器不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中的headers属性来进行匹配

在这里插入图片描述首先是对yml的修改

server:
  port: 8085
spring:
  application:
    name: provider-mode-workqueue
  rabbitmq:
    port: 5673
    host: 192.168.136.128
    username: admin
    password: admin
my:
  provider:
    queue1: myQueue1
    exchange: topicExchange
    queue2: myQueue2
    routing1: first.a.second.b
    routing2: first.b.second.c

然后对发送逻辑进行修改

@Component
public class Sender {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    private Environment env;

    public void send(){
        String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        Map<String,Object> map=new HashMap<>();
        map.put("createTime",createTime);
        rabbitTemplate.convertAndSend(env.getProperty("my.provider.exchange"),
         env.getProperty("my.provider.routing1"), map);
        rabbitTemplate.convertAndSend(env.getProperty("my.provider.exchange"),
         env.getProperty("my.provider.routing2"), map);
    }
}

然后消费者用上边的即可,不用修改。其实也不用启动消费者,看管理工具也是可以的,如下。
在这里插入图片描述同时最后消费的结果如下
在这里插入图片描述

六、RPC模式

在这里插入图片描述Rpc模式是通过客户端发送消息,服务端回复相应的消息,从而实现远程调用。

1.生产者

Config类需要改一下

@Configuration
public class Config {
    @Autowired
    private Environment env;

    @Bean
    public Queue myQueue(){

        return new Queue(env.getProperty("my.provider.queue1"));
    }

    @Bean
    public DirectExchange myExchange(){
        return new DirectExchange(env.getProperty("my.provider.exchange"));
    }

    @Bean
    public Binding binding(){
       return BindingBuilder.bind(myQueue())
                .to(myExchange())
                .with(env.getProperty("my.provider.routing1"));
    }
}

然后是发送的逻辑

@Component
public class Sender {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    private Environment env;

    public void  getPow(int x){
       System.out.println("### send " + x + "###");
       Object rep = rabbitTemplate.convertSendAndReceive(env.getProperty("my.provider.exchange"),
               env.getProperty("my.provider.routing1"), x);

       int res = (int) rep;
      System.out.println("### receive the answer is" + res + "  ###");
    }
}

最后是controller

@RestController
public class SendController {
    @Autowired
    Sender sender;
    @PostMapping("/get/{id}")
    public String send(@PathVariable(value = "id") int id){

        sender.getPow(id);
        return "ok";

    }
}

2.消费者

@Component
@RabbitListener(queues = "${my.consumer.queue1}")
public class Consumer {
    @RabbitHandler
    public int pow(Integer x) throws Exception{
        System.out.println("## receive" + x + "##");
        return  x * x;
    }
}

我们可以的到这样的测试结果
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值