springBoot整合RabbitMQ

在项目中有商品的变化,包括订单的一些状态变化需要用到RabbitMQ通知买家或者卖家,所以自己就去学习了一下。

1.RabbitMQ是什么?

采用AMQP高级消息队列协议的一种消息队列技术,最大的特点就是消费并不需要确保提供方存在,实现了服务之间的高度解耦

1.1什么是AMQP?

Advanced Message Queuing Protocol, 高级队列协议,协议层规范,就像http协议只要按照规范在任何平台都能用。RabbitMQ使用Erlang语言编写,支持多种协议,高可用,支持消息集群以及多语言客户端等等。

1.1.1 AMQP 中包含的主要元素

  • 生产者(Producer):向Exchange发布消息的应用。
  • 消费者(Consumer):从消息队列queue中消费消息的应用。
  • 消息队列(Message Queue):服务器组件,用于保存消息,直到发送给消费者。
  • Queue:消息载体;每个消息都会被投入到一个或多个队列。
  • 消息(Message):传输的内容。
  • 交换器(exchange):路由组件,接收Producer发送的消息,并根据Routing Key转发给消息队列queue。
  • Routing Key:路由关键字,exchange根据这个Routing Key进行消息投递到队列queue。
  • 绑定器(Binding):把exchange和queue按照路由规则绑定起来。

1.1.2 exchange 与 Queue 的路由机制

生产者发消息不需要指定Queue,消费者可以指定Queue绑定到某个RoutingKey和某个Exchange,也可以不指定Queue,就只根据某个Exchange和某个RoutingKey接受到消息。

Exchange 将消息发送到哪一个queue是由exchange type 和 Binding绑定规则决定的,目前常用的有3种exchange,Direct exchange, Fanout exchange, Topic exchange :

1.2 什么是JMS

java message server 它通过统一的java api层面的标准使得多个消息客户端来通过JMS交互,大部分消息中间件提供商都对JMS提供支持。比如ActiveMQ,JMS类似于JDBC,而这个ActiveMQ就像数据库驱动,JMS是一个规范,是一个标准,而ActivMQ则是一个具体的实现。JMS包括2种消息发布模型,点对点,发布者订阅者,只支持java平台

2.为什么要使用RabbitMQ?

  1. 在分布式系统下具备异步,削峰,负载均衡等一系列高级功能
  2. 拥有持久化的机制,进程消息,队列中的信息也可以保存下来。
  3. 实现消费者和生产者之间的解耦
  4. 对于高并发场景下,利用消息队列可以使得同步访问变为串行访问达到一定量的限流,利于数据库的操作
  5. 可以使用消息队列达到异步下单的效果,排队中,后台进行逻辑下单

3.使用RabbitMQ的场景

  1. 服务间异步通信
  2. 顺序消费
  3. 定时任务
  4. 请求削峰

4.RabbitMQ在springBoot中的使用

4.1 创建一个springBoot工程

在这里插入图片描述
选择rabbitMQ依赖
在这里插入图片描述
在这里插入图片描述

4.2 配置rabbitMQ

在这里插入图片描述

4.3设置Exchage策略

RabbitMQ提供了4种不同的Exchange策略,分别是Direct, Fanout,Topic,Header

  • Direct:所有发送到DirectExchange的消息将会被转发到RouteKey中指定的Queue
  • Fanout:所有发送到FanoutExchange的消息将会被转发到与该Exchange绑定(Binding)的所有的Queue
  • Topic:所有发送到TopicExchange的消息被将会被转发到所有关心Routekey指定Topic的Queue上,Exchange将RouteKey和某Topic进行模糊匹配。
  • Header:取消了RouteKey,使用了header中的key/value匹配队列

4.3.1 Direct

Direct的定义是 所有发送到DirectExchange的消息将会被转发到RouteKey中指定的Queue所有发送到DirectExchange的消息将会被转发到RouteKey中指定的Queue
先创建静态变量,用来记录状态的变化

package org.java.rabbitmq.base;


public class AmqpExchange {


    /**
     * 商品变化消息
     */
    public final static String GOODS_CHANGE = "GOODS_CHANGE";


    /**
     * 订单状态变化消息
     * 带入库的
     */
    public final static String ORDER_STATUS_CHANGE = "ORDER_STATUS_CHANGE";

    /**
     * 会员登录消息
     */
    public final static String MEMEBER_LOGIN = "MEMEBER_LOGIN";
}

在这里插入图片描述
然后创建商品的消费者

package org.java.rabbitmq.receiver;

import org.java.rabbitmq.base.AmqpExchange;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;



@Component
public class GoodsChangeReceiver {

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = AmqpExchange.GOODS_CHANGE + "_QUEUE"),
            exchange = @Exchange(value = AmqpExchange.GOODS_CHANGE)
    ))
    public void handler(String msg){
        System.out.println("商品变化信息-------------"+msg);
    }


}

接下来在test里面进行测试

package org.java.rabbitmq;

import org.java.rabbitmq.base.AmqpExchange;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class RabbitmqApplicationTests {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    void contextLoads() {
        rabbitTemplate.convertAndSend(AmqpExchange.GOODS_CHANGE + "_QUEUE","苹果库存-1");
    }




}

可以看到成功被消费
在这里插入图片描述

4.3.2 Fanout

Fanout的定义是 所有发送到FanoutExchange的消息将会被转发到与该Exchange绑定(Binding)的所有的Queue
Fanout也是用的最多的,像创建一个订单不仅仅 只发送到一个Queue,所有与之关联的都要
我们将type = ExchangeTypes 设置为Fanout,然后创建2个不同的Queue就行了

package org.java.rabbitmq.receiver;

import org.java.rabbitmq.base.AmqpExchange;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class OrderStatusChangeReceiver {
    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(value = AmqpExchange.ORDER_STATUS_CHANGE + "_QUEUE_ORDER",name = ""),
                    exchange = @Exchange(value = AmqpExchange.ORDER_STATUS_CHANGE,type = ExchangeTypes.FANOUT)
            ))
    public void orderChange(String msg){
        System.out.println("订单系统收到-------------"+msg);
    }

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(value = AmqpExchange.ORDER_STATUS_CHANGE + "_QUEUE_TRADE"),
                    exchange = @Exchange(value = AmqpExchange.ORDER_STATUS_CHANGE,type = ExchangeTypes.FANOUT)
            ))
    public void tradeChange(String msg){
        System.out.println("交易系统收到-------------"+msg);
    }

}

在这里插入图片描述
接下来在测试类里面测试

package org.java.rabbitmq;

import org.java.rabbitmq.base.AmqpExchange;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class RabbitmqApplicationTests {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    void contextLoads() {
        rabbitTemplate.convertAndSend(AmqpExchange.GOODS_CHANGE + "_QUEUE","苹果库存-1");
    }

    @Test
    public void test(){
        rabbitTemplate.convertAndSend(AmqpExchange.ORDER_STATUS_CHANGE,null,"订单号:k9527,状态:已创建");
    }



}

可以看到 与之相关的Queue 都被消费了
在这里插入图片描述

4.3.3 Topic

所有发送到TopicExchange的消息被将会被转发到所有关心Routekey指定Topic的Queue上,Exchange将RouteKey和某Topic进行模糊匹配。
定义说到需要将Routekey 进行模糊匹配,可是去哪设置呢?于是 我点开了@QueueBinding的源码,发现里面有个key,这个应该就是RoutKey。
在这里插入图片描述
在这里插入图片描述
接下来再创建一个有关登录的消费者,跟之前一样在@QueueBinding 添加一个key

package org.java.rabbitmq.receiver;

import org.java.rabbitmq.base.AmqpExchange;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class MemeberChangeReceiver {

    @RabbitListener(
            bindings = @QueueBinding(
                    key = "#.pc.#",
                    value = @Queue(value = AmqpExchange.MEMEBER_LOGIN + "_QUEUE_1"),
                    exchange = @Exchange(value = AmqpExchange.MEMEBER_LOGIN,type = ExchangeTypes.TOPIC)
            ))
    public void orderChange(String msg){
        System.out.println("pc登录:-------------"+msg);
    }

    @RabbitListener(
            bindings = @QueueBinding(
                    key = "huawei.#",
                    value = @Queue(value = AmqpExchange.MEMEBER_LOGIN + "_QUEUE_2"),
                    exchange = @Exchange(value = AmqpExchange.MEMEBER_LOGIN,type = ExchangeTypes.TOPIC)
            ))
    public void orderChange2(String msg){
        System.out.println("华为登录:-------------"+msg);
    }

    @RabbitListener(
            bindings = @QueueBinding(
                    key = "iphone.#",
                    value = @Queue(value = AmqpExchange.MEMEBER_LOGIN + "_QUEUE_3"),
                    exchange = @Exchange(value = AmqpExchange.MEMEBER_LOGIN,type = ExchangeTypes.TOPIC)
            ))
    public void orderChange3(String msg){
        System.out.println("苹果登录:-------------"+msg);
    }
}

其中xxxx.# 代表 以xxxx的开头的
#.xxxx.# 代表 以包含xxxx的
在这里插入图片描述
在测试类进行测试

package org.java.rabbitmq;

import org.java.rabbitmq.base.AmqpExchange;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class RabbitmqApplicationTests {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    void contextLoads() {
        rabbitTemplate.convertAndSend(AmqpExchange.GOODS_CHANGE + "_QUEUE","苹果库存-1");
    }

    @Test
    public void test(){
        rabbitTemplate.convertAndSend(AmqpExchange.ORDER_STATUS_CHANGE,null,"订单号:k9527,状态:已创建");
    }
    @Test
    public void test1(){
        rabbitTemplate.convertAndSend(AmqpExchange.MEMEBER_LOGIN,"iphone.wap","会员编号:00001,状态:登录");
        rabbitTemplate.convertAndSend(AmqpExchange.MEMEBER_LOGIN,"xiaomi.wap","会员编号:10001,状态:登录");
        rabbitTemplate.convertAndSend(AmqpExchange.MEMEBER_LOGIN,"huawei.pc","会员编号:900001,状态:登录");
    }


}

可以看到,结果与预期相符
在这里插入图片描述

4.3.4 Header

这个策略用得比较少,就不讲了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值