rabbit 整合springboot 2.1.3.RELEASE

MQ :

  1. rabbit还有些麻烦。 还要讲一些原理。
  2. rabbitmq的运作流程是需要了解的,不然的话会对使用有很大的阻碍;
  3. 我就不再写运行原理了,这篇文章写得不错(如果第一次用rabbitmq一定要看,5分钟就能懂): https://www.cnblogs.com/dwlsxj/p/RabbitMQ.html
随着不断的深入: 后面会发现rabbitmq的路由类型中topic可以代替其他direct、fanout这两种模式;


header模式目前还不清楚怎么回事。

topic: 因为topic路由有 * 和 # 的规则,所以可以代替fanout订阅模式;
direct: 可以直接由topic的固定写法代替(就是不使用topic的#、*的规则)

初学的可能开始看不懂,不过没关系,都试一遍就知道原因了。
  1. 想了解更多可以看看(也可以不看)
    
  在rabbitmq中,也可以按大方向分为: 生产消费模式、订阅模式
  因为rabbitmq的运行原理与activemq不同,所以理解也就不同;
  <p>
  在rabbitmq中,有几个概念:Message(要传输的数据)、Queue(装消息的队列名称)、Exchange(路由器)、routing Key(可以进行数据传输的队列匹配规则)、binding key (需要接收数据的队列)
  例如:
  1. 要传输的数据为(Message):"我要使用rabbitmq"
  2. 将上面要传输的数据放在3个Queue中, 并分别为Queue自定义取名: spring.rabbitmq.one 、 springboot.rabbitmq.two 、 springcould.rabbitmq.three
  3. 定义一个路由器(Exchange)【明白topic类型其实就足够了】[当然路由器有4种类型,不知道的自己去看看5分钟就懂了] ,将上面3个Queue 绑定到路由器(Exchange)上面
  4. 路由器设置routing Key (就是一个匹配的规则,跟他匹配上的上面自定义的Queue才能把消息发送到路由器上(Exchange)  )
  5. binding key (需要接收数据的队列) 也就是在接收端的监听注解上面加上要接收的Queue名称(也就是上面自定的3个中的Queue,可以都有,可以1个或者其他,也可以都没有[不过就不能接收消息了])
     

 下面这段话,一定要看可以学会了之后看。

在rabbitmq里,有各种默认行为:
如果我们不指定exchange,会有个默认的direct类型的exchange
如果不指定队列和交换器的绑定关系,默认就按消息的key绑定对应的queue。
此时发一个消息,消息的key是什么,就会被默认交换器送给对应的queue。

所以就存在为什么有些代码写的简单,还是能用的原因,如果知道原理后,用起来将会得心应手。

开始整合springboot:

 

消费端:

1. 引入依赖

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

2. 添加配置文件

spring:
  rabbitmq: ############################################### rabbitmq配置 ##############################################
    password: admin # 密码
    username: admin # 用户名
    port: 5673 # 端口号 5672用于常规连接(我这里是linux改成了5672),  5671用于使用TLS的连接
    host: 47.96.100.61 # ip
    publisher-confirms: true # 消息发送确认机制,防止消息丢失
    publisher-returns: true # 如果要进行消息回调,则这里必须要设置为true
    connection-timeout: 10s # 超时时间
    dynamic: true # 默认创建一个AmqpAdmin的Bean 默认为true
    requested-heartbeat: 2s # 请求的心跳超时时间

3. 配置数据 (根据自己情况配置,这里面自定义了 topic/fanout/direct)

package com.toad.config.rabbitmq;

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

/**
 * @author: wangqinmin
 * @date: 2019/3/29 16:54
 * @description: 仰天大笑出门去,我辈岂是蓬蒿人
 */
@Configuration
public class RabbitConfig {

    /**rabbitmq的路由类型有4种(常用生产消费模式:direct就可以了,topic其实也差不多就是有通配符显得更高级点):
     *
     * fanout	把所有发送到该Exchange的消息路由到所有与它绑定的Queue中(广播模式)
     * direct	Routing Key==Binding Key
     * topic	我这里自己总结的简称模糊匹配
     * headers	Exchange不依赖于routing key与binding key的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
     */

    /**
     * =================== fanout 模式  ====================
     * fanout属于广播模式,只要跟它绑定的队列都会通知并且接受到消息。
     */
    @Bean
    public Queue fanoutA() {
        return new Queue("fanout.a");
    }

    @Bean
    public Queue fanoutB() {
        return new Queue("fanout.b");
    }

    @Bean
    public Queue fanoutC() {
        return new Queue("fanout.c");
    }

    /**
     * =================== topic 模式  ====================
     * routing key为一个句点号"." 分隔的字符串 (如"stock.usd.nyse"、"nyse.vmw"、"quick.orange.rabbit")
     * binding key与routing key一样也是句点号"."分隔的字符串
     * binding key中可以存在两种特殊字符"*"与"#",用于做模糊匹配: (其中"*"用于匹配一个单词,"#"用于匹配多个单词(可以是零个))
     */
    @Bean
    public Queue topiocA() {
        return new Queue("topic.a");
    }

    @Bean
    public Queue topicB() {
        return new Queue("topic.b");
    }

    @Bean
    public Queue topicC() {
        return new Queue("topic.c");
    }

    /**
     * =================== direct 模式  ====================
     * direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中
     */
    @Bean
    public Queue directA() {
        return new Queue("directA");
    }

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

    /**
     * 自定义交换器
     * =================== 自定义一个fanout交换器 ===================
     * =================== 自定义一个topic交换器 ====================
     * =================== 自定义一个direct交换器 ====================
     */
    @Bean
    FanoutExchange fanoutExchange() {
        // 定义一个名为fanoutExchange的fanout交换器
        return new FanoutExchange("fanoutExchange");
    }

    @Bean
    TopicExchange topicExchange() {
        // 定义一个名为topicExchange的topic交换器
        return new TopicExchange("topicExchange");
    }

    @Bean
    DirectExchange directExchange() {
        // 定义一个名为directExchange的direct交换器
        return new DirectExchange("directExchange");
    }

    @Bean
    HeadersExchange headersExchange() {
        // 定义一个名为headersExchange的headers交换器
        return new HeadersExchange("headersExchange");
    }

    /**
     * 将队列与交换机绑定
     * =================== fanout 队列与交换机绑定  ====================
     */
    @Bean
    public Binding bindingExchangeWithA() {
        return BindingBuilder.bind(fanoutA()).to(fanoutExchange());
    }

    @Bean
    public Binding bindingExchangeWithB() {
        return BindingBuilder.bind(fanoutB()).to(fanoutExchange());
    }

    @Bean
    public Binding bindingExchangeWithC() {
        return BindingBuilder.bind(fanoutC()).to(fanoutExchange());
    }

    /**
     * 将队列与交换机绑定
     * =================== topic 队列与交换机绑定  ====================
     * 注意: 这里的写法; (这里的routing key :其实就是让写路由规则)
     */
    @Bean
    public Binding bindingTopicExchangeWithA() {
        return BindingBuilder.bind(topiocA()).to(topicExchange()).with("topic.msg");
    }

    @Bean
    public Binding bindingTopicExchangeWithB() {
        return BindingBuilder.bind(topicB()).to(topicExchange()).with("topic.#");
    }

    @Bean
    public Binding bindingTopicExchangeWithC() {
        return BindingBuilder.bind(topicC()).to(topicExchange()).with("topic.*.z");
    }

    /**
     * 将队列与交换机绑定
     * =================== direct 队列与交换机绑定  ====================
     */
    @Bean
    public Binding bindingDirectExchangeWithA() {
        return BindingBuilder.bind(directA()).to(directExchange()).with("directA");
    }

    @Bean
    public Binding bindingDirectExchangeWithB() {
        return BindingBuilder.bind(directB()).to(directExchange()).with("directB");
    }
}

4. 使用mq ,发送数据 例子:

package com.toad.swan.web.controller;

import com.alibaba.fastjson.JSON;
import com.toad.common.base.BaseController;
import com.toad.common.baseclass.ApiResult;
import com.toad.swan.entity.UUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

/**
 * @author: wangqinmin
 * @date: 2019/4/2 09:28
 * @description: 仰天大笑出门去,我辈岂是蓬蒿人
 */
@RestController
@RequestMapping("/RabbitMq")
@Slf4j
@Api("RabbitMq")
public class RabbitMqController extends BaseController {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    /**
     * 在rabbitmq中,也可以按大方向分为: 生产消费模式、订阅模式
     * 因为rabbitmq的运行原理与activemq不同,所以理解也就不同;
     * <p>
     * 在rabbitmq中,有几个概念:Message(要传输的数据)、Queue(装消息的队列名称)、Exchange(路由器)、routing Key(可以进行数据传输的队列)、binding key (需要接收数据的队列)
     * 例如:
     * 1. 要传输的数据为(Message):"我要使用rabbitmq"
     * 2. 将上面要传输的数据放在3个Queue中, 并分别为Queue自定义取名: spring.rabbitmq.one 、 springboot.rabbitmq.two 、 springcould.rabbitmq.three
     * 3. 定义一个路由器(Exchange)[当然路由器有4种类型,不知道的自己去看看5分钟就懂了] ,将上面3个Queue 绑定到路由器(Exchange)上面
     * 4. 路由器设置routing Key (就是一个匹配的规则,跟他匹配上的上面自定义的Queue才能把消息发送到路由器上(Exchange)  )
     * 5. binding key (需要接收数据的队列) 也就是在接收端的监听注解上面加上要接收的Queue名称(也就是上面自定的3个中的Queue,可以都有,可以1个或者其他,也可以都没有[不过就不能接收消息了])
     */


    /**
     * fanout属于广播模式,只要跟它绑定的队列都会通知并且接受到消息。
     * this.rabbitTemplate.convertAndSend(ExchangeType, routingKey, dateString);
     *
     * @param uUser
     * @return
     * @throws Exception
     */
    @PostMapping("/fanout")
    @ApiOperation(value = "rabbitmq异步添加用户", notes = "生产消费者模式", response = ApiResult.class)
    public Object addSysUser(@Valid @RequestBody UUser uUser) throws Exception {
        // 广播模式 routingKey 为空串就可以了。
        for(int i=0;i<10000;i++){
            this.rabbitTemplate.convertAndSend("fanoutExchange", "", JSON.toJSONString(uUser));
        }
        return success(true);
    }


    /**
     * topic模式 (如果你懂的话,就知道topic其实是一种分组模式)
     * this.rabbitTemplate.convertAndSend(ExchangeType, binding key, dateString);
     *
     * @param uUser
     * @return
     * @throws Exception
     */
    @PostMapping("/topic")
    @ApiOperation(value = "rabbit异步添加用户", notes = "发布、订阅模式", response = ApiResult.class)
    public Object addUser(@Valid @RequestBody UUser uUser) throws Exception {
        // 下面这种写法,就是所有topic类型路由器绑定Queue都能发送消息到rabbitmq中【跟topic模式识别规则有关】;
        // 注意: 这里的topic.a 已经不是routing key(topic模式,routing key 配置在配置文件中的) ,这里可以理解为binding key。
        this.rabbitTemplate.convertAndSend("topicExchange", "topic.a", JSON.toJSONString(uUser));
        return success(true);
    }

    /**
     * direct模式
     * this.rabbitTemplate.convertAndSend(ExchangeType, routingKey, dateString);
     *
     * @param uUser
     * @return
     * @throws Exception
     */
    @PostMapping("/direct")
    @ApiOperation(value = "rabbit异步添加用户", notes = "发布、订阅模式", response = ApiResult.class)
    public Object addUserInfo(@Valid @RequestBody UUser uUser) throws Exception {
        // 只有directA的队列(Queue)才能传输数据
        this.rabbitTemplate.convertAndSend("directExchange", "directA", JSON.toJSONString(uUser));
        return success(true);
    }
}

最后一步,就是接受rabbitmq的数据了,通常是另新建一个项目了。。

1. 引入依赖,跟上面一样。

2. application.yml的配置文件 ( 这里专门修改端口,方便使用测试 )

server:
  port: 8081  # 配置项目访问端口

spring:
  rabbitmq: ############################################### rabbitmq配置 ##############################################
    password: admin # 密码
    username: admin # 用户名
    port: 5673 # 端口号 5672用于常规连接(我这里是linux改成了5672),  5671用于使用TLS的连接
    host: 47.96.100.61 # ip
    publisher-confirms: true # 消息发送确认机制,防止消息丢失
    publisher-returns: true # 如果要进行消息回调,则这里必须要设置为true
    connection-timeout: 10s # 超时时间
    dynamic: true # 默认创建一个AmqpAdmin的Bean 默认为true
    requested-heartbeat: 2s # 请求的心跳超时时间

3. 消费数据了:

唯一需要根据情况修改的地方:@RabbitListener(queues = {"自定义的queue"})

package com.rabbitmq.mq.fanout;


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

/**
 * @author: wangqinmin
 * @date: 2019/3/29 17:28
 * @description: 仰天大笑出门去,我辈岂是蓬蒿人
 * @description fanout模式消费者
 */
@Component
// 消费端,不同的Queue这里的监听不同
@RabbitListener(queues = {"fanout.a"})
public class FanoutA2Consumer {
    
    /**
     * 消息消费
     *
     * @RabbitHandler 代表此方法为接受到消息后的处理方法
     */
    @RabbitHandler
    public void recieved(String msg) {
        System.out.println("FanoutA2Consumer [fanout.a]:" + msg);
    }
}

完工 !

源码也是有的,有兴趣的再找我要吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值