RabbitMQ基础(2)——发布订阅 fanout模式 & topic模式 & rabbitmq回调确认 & 延迟队列(死信

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

@Bean
public Binding mailBinding(){
    return BindingBuilder.bind(mailQueue())
            .to(fanoutExchange());
}

@Bean
public Binding phoneBinding(){
    return BindingBuilder.bind(phoneQueue())
            .to(fanoutExchange());
}

}


### 生产者生成验证码,发送给交换机



> 
> 接口
> 
> 
> 



package com.tianju.auth.service;

public interface IUserService {

/\*\*

* 生产者生成信息发送给交换机
* @param msg 信息,这里是验证码
*/
void sendCode(String msg);
}



> 
> 实现
> 
> 
> 



package com.tianju.auth.service.impl;

import com.tianju.auth.service.IUserService;
import com.tianju.auth.util.RabbitMqConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class UserServiceImpl implements IUserService {

@Autowired
private RabbitTemplate rabbitTemplate;

@Override
public void sendCode(String msg) {
    rabbitTemplate.convertAndSend(
            RabbitMqConstants.MQ\_FANOUT\_EXCHANGE,
            "routingkey.fanout",
            msg);
    log.debug("[生产者向交换机:] 发送一条信息:{}",msg);
}

}



> 
> 测试类生成验证码,发给交换机
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/60bd08eab3a54dc083f1462219e4ccd7.png)



package com.tianju.auth.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.tianju.auth.service.IUserService;

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.SpringJUnit4ClassRunner;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)

public class UserServiceImplTest {

@Autowired
private IUserService userService;

@Test
public void sendCode() {
    String code = new Snowflake().nextIdStr().substring(0, 6);
    System.out.println(code);
    userService.sendCode(code);
}

}


### 消费者消费验证码



package com.tianju.auth.consumer;

import com.tianju.auth.service.IEmailService;
import com.tianju.auth.util.RabbitMqConstants;
import com.tianju.auth.util.SMSUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class UserConsumer {
@Autowired
private IEmailService emailService;

@RabbitListener(queues = RabbitMqConstants.MQ\_MAIL\_QUEUE)
public void emailConsumer(String msg){
    log.debug("[email消费者:]消费{}",msg);
    emailService.sendEmail("xxxx@qq.com", "登陆验证码", msg);
}

@RabbitListener(queues = RabbitMqConstants.MQ\_PHONE\_QUEUE)
public void phoneConsumer(String msg){
    log.debug("[phone消费者:]消费{}",msg);
    SMSUtil.send("xxxx", msg);
}

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/ded10b5c9ff7438ba9e9b840ef547fcd.png)


## topic模式


![在这里插入图片描述](https://img-blog.csdnimg.cn/2585b426376e4860be43576eada8088a.png)



> 
> 例如: routingkey: my.orange.rabbit —-> Q1,Q2
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/5bbb30c09947481a95cb66771c21ccd1.png)


### 配置类增加配置



package com.tianju.auth.util;

/**
* rabbitmq的常量
*/
public interface RabbitMqConstants {
String MQ_MAIL_QUEUE=“mq_email_queue”;
String MQ_PHONE_QUEUE=“mq_phone_queue”;
String MQ_FANOUT_EXCHANGE=“mq_fanout_exchange”;

String MQ\_TOPIC\_EXCHANGE="mq\_topic\_exchange";

String MQ\_TOPIC\_QUEUE\_A = "mq\_topic\_queue\_a";
String MQ\_TOPIC\_QUEUE\_B = "mq\_topic\_queue\_b";

// 参数 String name, boolean durable, boolean exclusive, boolean autoDelete
boolean durable = true;
boolean exclusive = false;
boolean autoDelete = false;

}



package com.tianju.auth.config;

import com.tianju.auth.util.RabbitMqConstants;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMqConfig {

@Bean // 邮箱的队列
public Queue mailQueue(){
    return new Queue(RabbitMqConstants.MQ\_MAIL\_QUEUE,
            RabbitMqConstants.durable,
            RabbitMqConstants.exclusive,
            RabbitMqConstants.autoDelete);
}

@Bean // 电话的队列
public Queue phoneQueue(){
    return new Queue(RabbitMqConstants.MQ\_PHONE\_QUEUE,
            RabbitMqConstants.durable,
            RabbitMqConstants.exclusive,
            RabbitMqConstants.autoDelete);
}
@Bean // 交换机
public FanoutExchange fanoutExchange(){
    return new FanoutExchange(RabbitMqConstants.MQ\_FANOUT\_EXCHANGE,
            RabbitMqConstants.durable,
            RabbitMqConstants.autoDelete);
}

@Bean
public Binding mailBinding(){
    return BindingBuilder.bind(mailQueue())
            .to(fanoutExchange());
}

@Bean
public Binding phoneBinding(){
    return BindingBuilder.bind(phoneQueue())
            .to(fanoutExchange());
}



@Bean // A队列
public Queue topicAQueue(){
    return new Queue(RabbitMqConstants.MQ\_TOPIC\_QUEUE\_A,
            RabbitMqConstants.durable,
            RabbitMqConstants.exclusive,
            RabbitMqConstants.autoDelete);
}

/\*\*

* topic模式相关配置
*/

@Bean // B队列
public Queue topicBQueue(){
    return new Queue(RabbitMqConstants.MQ\_TOPIC\_QUEUE\_B,
            RabbitMqConstants.durable,
            RabbitMqConstants.exclusive,
            RabbitMqConstants.autoDelete);
}

@Bean // topic的交换机
public TopicExchange topicMyExchange(){
    return new TopicExchange(RabbitMqConstants.MQ\_TOPIC\_EXCHANGE,
            RabbitMqConstants.durable,
            RabbitMqConstants.autoDelete);
}


@Bean
public Binding topicAQueueBinding(){
    return BindingBuilder
            .bind(topicAQueue())
            .to(topicMyExchange())
            .with("topic.xxx"); // 规则 topic.xxx
}

@Bean
public Binding topicBQueueBinding(){
    return BindingBuilder
            .bind(topicBQueue())
            .to(topicMyExchange())
            .with("topic.\*"); // 规则 topic.xxx
}

}


### 生产者发送信息


![在这里插入图片描述](https://img-blog.csdnimg.cn/1481ecc9efaf41c091714b82c1bc347c.png)



/\*\*

* topic模式下,生产者发送信息给交换机,可以决定给哪个队列发信息
* @param msg 发送的信息
* @param routingKey 类似正则表达式,决定给谁发
* .with(“topic.xxx”); // 规则 topic.xxx ---- A队列
* .with(“topic.*”); // 规则 topic.xxx ---- B队列
* 在配置类中,如上所述配置,则如果输入的routingKey为 topic.xxx则给A和B发;
* 如果输入的routingKey为 topic.yyy 则 只给B队列发;
*/
void sendMsg(String msg,String routingKey);



> 
> 实现
> 
> 
> 



package com.tianju.auth.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianju.auth.entity.UserPrivs;
import com.tianju.auth.mapper.UserMapper;
import com.tianju.auth.service.IUserService;
import com.tianju.auth.util.RabbitMqConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class UserServiceImpl implements IUserService {

@Autowired
private RabbitTemplate rabbitTemplate;

@Override
public void sendCode(String msg) {
    rabbitTemplate.convertAndSend(
            RabbitMqConstants.MQ\_FANOUT\_EXCHANGE,
            "routingkey.fanout",
            msg);
    log.debug("[生产者向交换机:] 发送一条信息:{}",msg);
}

@Override
public void sendMsg(String msg,String routingKey) {
    rabbitTemplate.convertAndSend(
            RabbitMqConstants.MQ\_TOPIC\_EXCHANGE,
            routingKey, // "topic.yyy",此时只有B队列有信息
            msg);
    log.debug("[生产者向交换机:] 发送一条信息:{}",msg);
}

}


### 进行发送



package com.tianju.auth.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.tianju.auth.service.IUserService;

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.SpringJUnit4ClassRunner;

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)

public class UserServiceImplTest {

@Autowired
private IUserService userService;

@Test
public void sendCode() {
    String code = new Snowflake().nextIdStr().substring(0, 6);
    System.out.println(code);
    userService.sendCode(code);
}

@Test
public void sendTopic() {
    String code = new Snowflake().nextIdStr().substring(0, 6);
    System.out.println(code);
    userService.sendMsg(code,"topic.yyy");
}

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/dc40f7009a5e4067b60957ebebb4483b.png)


### 控制台查看


![在这里插入图片描述](https://img-blog.csdnimg.cn/214dd8bb1a8549ec9dd99fe23bb9586c.png)


## rabbitmq回调确认


### 配置类



spring:

rabbitmq的配置

rabbitmq:
host: 192.168.111.130
port: 5672
username: admin
password: 123
# 确认收到
publisher-confirm-type: correlated
publisher-returns: true


### 验证生产者发送是否成功



> 
> 使用RabbitTemplate的回调方法。
> 
> 
> 先设置
> 
> 
> * setConfirmCallback
> * setReturnsCallback
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/29c69a9533834a688520fa380ca3d84d.png)



@Autowired
private RabbitTemplate rabbitTemplate;

@Override
public void sendCode(String msg) {
    rabbitTemplate.convertAndSend(
            RabbitMqConstants.MQ\_FANOUT\_EXCHANGE,
            "routingkey.fanout",
            msg);
    log.debug("[生产者向交换机:] 发送一条信息:{}",msg);
}

@Override
public void sendMsg(String msg,String routingKey) {

    // 如果发到交换机,看一下有没有反馈
    rabbitTemplate.setConfirmCallback((c,ack,message)->{
        log.debug("\*\*\*\*\* setConfirmCallback:ack--{}", ack); // 是否发送到交换机
        log.debug("\*\*\*\*\* setConfirmCallback:c-->{}",c);
        // channel error; protocol method: #method<channel.close>(reply-code=404,
        // reply-text=NOT\_FOUND - no exchange 'aaaa' in vhost '/', class-id=60, method-id=40)
        log.debug("\*\*\*\*\* setConfirmCallback:m-->{}",message);
        if (ack){
            log.debug("[生产者:] 发送信息到交换机{}","RabbitMqConstants.MQ\_TOPIC\_EXCHANGE");
        }else {
            log.debug(message);
        }
    });

    rabbitTemplate.setReturnsCallback(r->{
        log.debug("返回文字{}", r.getReplyText());
        log.debug("返回code{}", r.getReplyCode());
        log.debug("返回Exchange{}", r.getExchange());
        log.debug("返回RoutingKey{}", r.getRoutingKey());
    });


    rabbitTemplate.convertAndSend(
            RabbitMqConstants.MQ\_TOPIC\_EXCHANGE,

// “aaaa”,// 失败的情况
routingKey, // “topic.yyy”,此时只有B队列有信息
msg);

    log.debug("[生产者向交换机:] 发送一条信息:{}",msg);
}

![在这里插入图片描述](https://img-blog.csdnimg.cn/add6f272ff754d5aa96bc788bc0f9b18.png)



rabbitTemplate.setConfirmCallback((c,ack,message)->{
log.debug(“******* setConfirmCallback:ack->{}”,ack);
log.debug(“******* setConfirmCallback:c->{}”,c);
log.debug(“******* setConfirmCallback:chanel->{}”,message);
if(ack){
log.debug(“[生产者]发送信息到达交换机{}”,“RabbitMqConstants.MQ_TOPIC_EXCHANGE”);
}else {
log.debug(message);
}
});
rabbitTemplate.setReturnsCallback(r->{
log.debug(“返回文字:{}”,r.getReplyText());
log.debug(“返回code:{}”,r.getReplyCode());
log.debug(“返回Exchange:{}”,r.getExchange());
log.debug(“返回RoutingKey:{}”,r.getRoutingKey());
});
rabbitTemplate.convertAndSend(
RabbitMqConstants.MQ_TOPIC_EXCHANGE,
“abc.xxx”,
msg
);



@Test
public void sendTopic() {
    String code = new Snowflake().nextIdStr().substring(0, 6);
    System.out.println(code);
    userService.sendMsg(code,"topic.rrr");
}

## 延迟队列(死信)设计


[Documentation: Table of Contents — RabbitMQ]( )


![在这里插入图片描述](https://img-blog.csdnimg.cn/8d012596a93d45acaf606bcef7dde082.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/15d187f391624fa6aa3905df97230d56.png)


### java代码步骤


#### 创建正常+死信队列



package com.tianju.mq.config;

import com.tianju.mq.constants.RabbitMqConstants;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class RabbitMqConfig {

@Bean
public DirectExchange normalExchange(){
    return new DirectExchange(RabbitMqConstants.MQ\_NORMAL\_EXCHANGE,
            RabbitMqConstants.durable,
            RabbitMqConstants.autoDelete);
}
@Bean
public Queue normalQueue(){
    Map<String, Object> map = new HashMap<>(2);
    map.put("x-dead-letter-exchange",RabbitMqConstants.MQ\_DELAY\_EXCHANGE);
    map.put("x-dead-letter-routing-key",RabbitMqConstants.MQ\_DELAY\_ROUTING\_KEY);
    return new Queue(
            RabbitMqConstants.MQ\_NORMAL\_QUEUE,
            RabbitMqConstants.durable,
            RabbitMqConstants.exclusive,
            RabbitMqConstants.autoDelete,
            map);
}
@Bean
public Binding normalBinding(){
    return BindingBuilder.bind(normalQueue())
            .to(normalExchange())
            .with(RabbitMqConstants.MQ\_NORMAL\_ROUTING\_KEY);
}


//------------------死信队列设计--------------------------
/\*\*

* 死信(延迟)队列
* @return
*/
@Bean
public Queue delayQueue(){
return new Queue(RabbitMqConstants.MQ_DELAY_QUEUE,
RabbitMqConstants.durable,
RabbitMqConstants.exclusive,
RabbitMqConstants.autoDelete);
}
/**
* 死信交换机
* @return
*/
@Bean
public DirectExchange delayExchange(){
return new DirectExchange(RabbitMqConstants.MQ_DELAY_EXCHANGE,
RabbitMqConstants.durable,
RabbitMqConstants.autoDelete);
}
/**
* 死信交换机队列绑定
* @return
*/
@Bean
public Binding delayBinding(){
return BindingBuilder.bind(delayQueue())
.to(delayExchange())
.with(RabbitMqConstants.MQ_DELAY_ROUTING_KEY);
}
}


#### 配置类+常量



package com.tianju.mq.constants;

public interface RabbitMqConstants {
String MQ_DELAY_QUEUE = “mq_delay_queue”; // 延迟队列,死信队列
String MQ_DELAY_EXCHANGE = “mq_delay_exchange”; // 死信交换机
String MQ_DELAY_ROUTING_KEY = “mq_delay_routing_key”; // 死信路由

// 正常的队列,交换机,路由
String MQ\_NORMAL\_QUEUE = "mq\_normal\_queue";
String MQ\_NORMAL\_EXCHANGE = "mq\_normal\_exchange";
String MQ\_NORMAL\_ROUTING\_KEY = "mq\_normal\_routing\_key";

// 参数
boolean durable = true;
boolean exclusive = false;
boolean autoDelete = false;

}



server:
port: 9099

spring:

邮箱的配置

mail:
host: smtp.qq.com
port: 587
username: xxxxx.com
password: xxxxx

rabbitmq的配置

rabbitmq:
host: 192.168.111.130
port: 5672
username: admin
password: 123
# 确认收到
publisher-confirm-type: correlated
publisher-returns: true

logging:
level:
com.tianju.mq: debug


### 生产者到正常队列



package com.tianju.mq.service;

public interface IUserService {
/**
* 延迟队列的生产者
* @param msg 发送的信息
* @param delayTime 延迟的时间,毫秒
*/
void sendDelay(String msg,int delayTime);
}



package com.tianju.mq.service.impl;

import com.tianju.mq.constants.RabbitMqConstants;
import com.tianju.mq.service.IUserService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

`
package com.tianju.mq.service.impl;

import com.tianju.mq.constants.RabbitMqConstants;
import com.tianju.mq.service.IUserService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service

[外链图片转存中…(img-u2B9pptr-1715282502426)]
[外链图片转存中…(img-LnKlcIoB-1715282502427)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值