【RabbitMQ】(03)Springboot整合RabbitMQ

(1)创建Springboot项目

在Springboot中使用RabbitMQ就十分简单了,因为RabbitMQ做了一些封装,而且Springboot天生支持RabbitMQ,所以很容易操作。

在这里插入图片描述

提供了RabbitMQ的模板RabbitTemplate,用来简化操作,向服务器发送信息。使用的时候直接在项目中注入即可,开箱即用

(2)hello模型

一个生产者对应一个消费者
在这里插入图片描述
(1)hello模型-创建生产者(直接在test里面编写)
在这里插入图片描述代码如下:

@SpringBootTest(classes = SpringbootRabbitmqApplication.class)
@RunWith(SpringRunner.class)
public class TestRabbitMQ {

    //注入模板RabbitTemplate
    @Autowired
    private RabbitTemplate rabbitTemplate;

    //helloword的模型,队列的创建不是在生产者这边创建,而是在消费者那边创建的,所以只运行生产者在服务器里是看不到创建队列的
    @Test
    public void test(){
        //hello是队列的名称,队列的消息内容是helloworld
        rabbitTemplate.convertAndSend("hello","helloworld");
    }
    
}

但是此时启动运行,进入服务器看到没有消息队列的创建,这是因为队列的创建不是在生产者这边创建,而是在消费者那边创建的,所以只运行生产者在服务器里是看不到创建队列的。接下来我们要接着创建一个消费者,然后再进行测试~

(2)创建消费者(写一个Controller)

代码如下:

@Component
//queuesToDeclare表示没有队列就声明一个队列
//指定队列的名字hello
@RabbitListener(queuesToDeclare = @Queue("hello"))//消费者的一个监听
public class HelloController {

    //上面已经指定了消息队列,现在就要用这个方法去接受消息,下面的message指的就是消息
    @RabbitHandler//表示这是取出消息队列后对应的处理方法
    public void recieve01(String message){
        System.out.println("message = "+message);
    }
}

(3)启动运行看结果
可以看到运行的时候,前台控制器已经打印出来消息的内容了,说明消费者已经接收到了生产者发送的消息
在这里插入图片描述
再到服务器中看一下:
在这里插入图片描述

(2)Work queues:工作队列

一个生产者产生的消息可以供多个消费者消费,但是一个消息只能被其中一个消费者消费。
在这里插入图片描述
(1)创建生产者

    @Test
    public void testWorkQueues(){
        rabbitTemplate.convertAndSend("work","workqueues模型");
    }

(2)创建消费者

@Component
public class WorkConsummer {


    //第一个消费者
    //这个注解不仅可以加在类上,当有多个方法时,还可以加在方法上
    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void recieve01(String message){
        System.out.println("message01 = "+message);
    }

    //第二个消费者
    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void recieve02(String message){
        System.out.println("message02 = "+message);
    }
}

(3)测试结果
可以看到,消息被其中一个消费者接收到了
在这里插入图片描述
在这里插入图片描述
(4)修改成发布多条消息,看看两个消费者的接受情况

    @Test
    public void testWorkQueues(){
        for (int i = 0; i < 10; i++) {
            rabbitTemplate.convertAndSend("work","workqueues模型"+i);
        }
    }

(5)再测试看结果
可以看到work模型的分配方法是“公平分配”
在这里插入图片描述

(3)publish/Subscribe:发布订阅的模型(fanout广播模型)

多了一个交换机,生产者将消息发送到交换机上,交换机发送消息给各个队列,此时,一个消息可以被多个消费者获取。
值得一提的是,这又叫广播模式,是最常用的模式了,在ITOO中使用的就是这种模式。

在这里插入图片描述
生产者先给交换机发送消息,然后交换机广播给多个消费者的消息队列,然后消费者再到消息队列中取出消息

(1)生产者

    @Test
    public void testFanout(){
        rabbitTemplate.convertAndSend("logs","Fanout模型发送的消息");
    }

(2)消费者

@Component
public class FanoutConsummer {

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,//创建临时队列
                    exchange = @Exchange(value = "logs",type = "fanout")//绑定的交换机
            )
    })
    public void recieve01(String message){
        System.out.println("message01 = "+message);
    }

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,//创建临时队列
                    exchange = @Exchange(value = "logs",type = "fanout")//绑定的交换机
            )
    })
    public void recieve02(String message){
        System.out.println("message02 = "+message);
    }
}

(4)路由:Routing模型

又多了一个routing key,生产者发送消息带有routingkey,消费者选择自己需要的消息进行消费,也配置一个routing key。

在这里插入图片描述
比fanout广播的模式多一点,多的就是一个rountingKey,可以根据不同的rountingKey来转向不同的消息队列

(1)生产者

    @Test
    public void testRoute(){
        rabbitTemplate.convertAndSend("directs","info","发送info的key的路由信息");
    }

(2)消费者

key = {“error”}的消费者是接收不到消息的,因为routingKey不匹配

@Component
public class RouteConsummer {

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,//创建临时队列
                    exchange = @Exchange(value = "directs",type = "direct"),//绑定的交换机
                    key = {"info","error","warn"}
            )
    })
    public void recieve01(String message){
        System.out.println("message01 = "+message);
    }

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,//创建临时队列
                    exchange = @Exchange(value = "directs",type = "direct"),//绑定的交换机
                    key = {"error"}
            )
    })
    public void recieve02(String message){
        System.out.println("message02 = "+message);
    }
}

(3)运行结果
在这里插入图片描述

在这里插入图片描述

(6)Topic模式:动态路由

主题模式:又多了一个通配符,这样消费端如果需要好几种消息的时候,不用一个一个的设置,直接用通配符可以接收自己想要的各种消息。

在这里插入图片描述
(1)生产者

    //动态路由,订阅模式
    @Test
    public void testTopic(){
        rabbitTemplate.convertAndSend("topics","user.save","user.save路由消息");
    }

(2)消费者

@Component
public class TopicConsummer {
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,//创建临时队列
                    exchange = @Exchange(type = "topic",name = "topics"),//绑定的交换机
                    key = {"user.save","user.*"}
            )
    })
    public void recieve01(String message){
        System.out.println("message01 = "+message);
    }

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,//创建临时队列
                    exchange = @Exchange(type = "topic",name = "topics"),//绑定的交换机
                    key = {"order.#","produce.#","user.*"}
            )
    })
    public void recieve02(String message){
        System.out.println("message02 = "+message);
    }
}

(3)运行结果
在这里插入图片描述

在这里插入图片描述

(7)应用场景

RabbitMQ以至于MQ的应用场景有4个:异步处理、应用解耦、流量削峰、日志处理。

(7.1)异步处理

用户注册以后,需要发送注册邮件和注册短信,传统的做法有两种:串行和并行
串行和并行的效率较慢,使用消息队列效率较高。

像10086,我们在app买票成功后,它会提示我们“购票成功”,然后过一会就会收到短信,提示你出票成功,座位号之类的。
又或者,当你在一个网站新注册后,这个网站会给你发邮件和短信,祝贺你注册成功。
有3种供选方案:
(1)串行方式
在这里插入图片描述这种方式是最笨的,就是先写入数据库,然后发送邮件,最后发送短信,都成功以后,才会返回给用户“注册成功”

(2)并行方式
在这里插入图片描述这种方式进行了优化,就是写入数据库后,同时发送邮件和短信,任务完成后,将结果返回给用户

(3)使用消息队列
在这里插入图片描述我们可以想想,发送邮件和短信是必须的吗?不是。这种方式的流程是:先写入数据库,然后写入消息队列,最后将结果返还给用户。至于发送邮件和短信,可以在之后进行。这样,对于用户来说,等待的时候大大减少了。

(7.2)应用解耦

场景引入:
用户下单后,订单系统需要通知库存系统减少库存。
供选方案:
(1)用户下单后,订单系统调用库存系统的接口,通知库存系统要减少库存。
在这里插入图片描述(2)用户下单后,订单系统完成持久化处理后,将消息写入消息队列,返回用户订单下单成功。
库存系统订阅下单信息,采用拉/推的方式,获取下单信息后,进行库存操作。
在这里插入图片描述比较:显然,第(2)种比第一种更先进,消解了订单系统和库存系统之间的耦合

(7.3)流量削峰

在这里插入图片描述在秒杀活动中,极短的时间内,有大量的请求涌入,如果都从数据库层面操作,就会让数据库瘫痪。
解决办法就是加入消息队列,这样就将请求“积压”在了消息队列中,数据库能尽可能多地调用就调,调用不了的可以先存着。
当然,消息队列也有满的时候,如果超过了容量,它就会直接抛弃用户请求或跳转到错误页面。

(7.4)日志处理

在这里插入图片描述日志处理和流量削峰的过程大致一样,解决的是大量日志传输的问题。Rabbitmq也能进行日志处理,但是我们一般使用Kafka进行日志处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值