Springboot整合RabbitMQ

1.进入jar包

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

2.声明队列、交换机、交换机与队列绑定关系(不需要则不声明,比如简单模式和工作队列模式只需要声明队列)

@Bean
public Queue orderDirectQueue() {
    return new Queue(MQQueueEnum.DIRECT_QUEUE_ORDER.getName(), true, false,false);
}
@Bean
public DirectExchange orderDirectExchange() {
    return new DirectExchange(MQExchangeEnum.EXCHANGE_DIRECT_ORDER.getName(), true, false);
}

@Bean
public Binding bindingDirect() {
    return BindingBuilder.bind(orderDirectQueue())
            .to(orderDirectExchange())
            .with(MQQueueEnum.DIRECT_QUEUE_ORDER.getRoutingKey());
}

3.构建消息发送者

private RabbitTemplate rabbitTemplate;

@Autowired
public void setRabbitTemplate(RabbitTemplate rabbitTemplate) {
    this.rabbitTemplate = rabbitTemplate;
    this.rabbitTemplate.setEncoding("UTF-8");
    this.rabbitTemplate.setConfirmCallback(confirmCallback);
    this.rabbitTemplate.setReturnCallback(returnCallback);
    this.rabbitTemplate.setReplyTimeout(60000);
}
public void sendOrder(String message){
    logger.info("发送在线商城订单创建消息: {}", message);
    sendMsg(MQExchangeEnum.EXCHANGE_DIRECT_ORDER.getName(), MQQueueEnum.DIRECT_QUEUE_ORDER.getRoutingKey(), message, new CorrelationData(RandomUtils.getUUID()));
}

private void sendMsg(String exchangeName, String routingKey, Object request, CorrelationData correlationData) {
    rabbitTemplate.convertAndSend(exchangeName, routingKey, request, message -> {
        message.getMessageProperties().getHeaders().put("spring_returned_message_correlation", correlationData.getId());
        message.getMessageProperties().getHeaders().put("send_ip", getLocalIp());
        return message;
    }, correlationData);
}

private String getLocalIp() {
    try {
        return WebToolUtils.getLocalIP();
    } catch (Exception e) {
        logger.error("获取本地IP异常", e);
    }
    return "0.0.0.0";
}

4.构建消息消费者

@Component

public class OnlineShopOrderReceiver {

    private static Logger logger = LoggerFactory.getLogger(OnlineShopOrderReceiver.class);

    @RabbitListener(queues = {"onlineshop.order.queue.direct"}, errorHandler = "rabbitListenerErrorHandler")
    public void onMessage(Channel channel, Message message) throws IOException, InterruptedException {
        logger.info("收到在线商城订单创建{}发送的消息{}", message.getMessageProperties().getHeaders().get("send_ip"), message);
        //如果不写basicQos(1),则自动MQ会将所有请求平均发送给所有消费者
        //basicQos,MQ不再对消费者一次发送多个请求,而是消费者处理完一个消息后(确认后),在从队列中获取一个新的
        // 处理完业务再取下一条
        //channel.basicQos(1);
        //Thread.sleep(5000);
        try {
            Object correlation = message.getMessageProperties().getHeaders().get("spring_returned_message_correlation");
            if (correlation == null) {
                logger.info("收到错误消息: {}", message);
            } else {
                logger.info("消息处理: {}", new String(message.getBody()));
            }
        } finally {
           channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

}

5.配置文件需要配置MQ连接信息

# 配置RabbitMQ的基本信息  ip 端口 username  password..
spring:
  rabbitmq:
    host: #ip
    port: 5672
    username: admin
    password: 123456
    virtual-host: /
    publisher-confirms: true
    publisher-returns: true
    template:
      mandatory: true
      retry:
        enabled: true
        initial-interval: 3000ms
        max-attempts: 3
        max-interval: 10000ms
        multiplier: 1
    #配置消费端
    listener:
      direct:
        acknowledge-mode: manual
      simple:
        acknowledge-mode: manual
        #最小的消费者数量
        concurrency: 5
        #消费失败后从新消费
        #决定被拒绝的消息是否重新入队;默认是true(与参数acknowledge-mode有关系)
        default-requeue-rejected: true
        #最大的消费者数量
        max-concurrency: 5
        #一个消费者最多可处理的nack消息数量,如果有事务的话,必须大于等于transaction数量
        prefetch: 1
        retry:
          #监听重试是否可用
          enabled: true
          #第一次和第二次尝试传递消息的时间间隔
          initial-interval: 1000ms
          #最大重试次数
          max-attempts: 5
          #最大重试时间间隔
          max-interval: 10000ms
          #应用于上一重试间隔的乘数
          multiplier: 1.0
          #重试时有状态or无状态
          stateless: false

 RabbitMQ高级特性

1.消息的可靠性投递

springboot开启confirm,return模式

publisher-confirms: true

publisher-returns: true

/**
 * 回调函数: confirm确认 如果消息没有到exchange,则confirm回调,ack=false 如果消息到达exchange,则confirm回调,ack=true
 * publisher-confirms,实现一个监听器用于监听broker端给我们返回的确认请求:
 */
final RabbitTemplate.ConfirmCallback confirmCallback =
        (correlationData, ack, cause) -> logger.info("correlationData: {}  ack:{}", correlationData, ack);

/**
 * 回调函数: return返回
 * exchange到queue成功,则不回调
 * exchange到queue失败,则回调
 * publisher-returns,保证消息对broker端是可达的,如果出现路由键不可达的情况,
 * 则使用监听器对不可达的消息进行后续的处理,保证消息的路由成功:
 * RabbitTemplate.ReturnCallback 注意:设置
 * spring.rabbitmq.template.mandatory=true保证ReturnCallback监听有效
 */
final RabbitTemplate.ReturnCallback returnCallback =
        (message, replyCode, replyText, exchange, routingKey) ->
        logger.info("消息{}不可达,exchange: {}, routingKey: {}, replyCode: {}, replyText: {}",
            message.toString(), exchange, routingKey, replyCode, replyText);

 消费端设置消息签收

listener:
  simple:
    acknowledge-mode: manual/none

manual:手动确认(推荐使用),消息手动签收后,才会从队列中清空,如果此处业务处理异常,可以不签收,调用channel.basicNack回退给队列,让队列自动重新发送(一般不这么做),如果异常一直存在的话,消息会不断的发送,造成网络开销,建议签收然后将异常的消息放入缓存或数据库,手动处理。

none:自动确认,消息会在消费端自动签收,如果消息处理异常也不会重新发送消息了,造成了消息丢失。

保证消息可靠性

  1. 持久化--交换机持久化,队列持久化,消息持久化
  2. 生成端--confirm+return消息确认机制
  3. 消费端--消息签收处理
  4. Broker要高可用

2.消费端限流

可用设置一次性从队列中拉取多少条消息,消息签收一定要设置为手动签收

listener:
  simple:
    acknowledge-mode: manual
    prefetch: 1

如果从队列中拉取全量消息,势必会对消费端造成压力

3.TTL 

Time To Live 存活时间,可用设置每条消息存活时间

private void sendMsg(String exchangeName, String routingKey, Object request, CorrelationData correlationData) {
    rabbitTemplate.convertAndSend(exchangeName, routingKey, request, message -> {
        message.getMessageProperties().getHeaders().put("spring_returned_message_correlation", correlationData.getId());
        message.getMessageProperties().getHeaders().put("send_ip", getLocalIp());
        // 设置TTL消息过期时间
        message.getMessageProperties().setExpiration("10000");
        return message;
    }, correlationData);

也可以设置队列中全部消息存活时间,在声明队列时设置:

@Bean
public Queue orderDirectQueue() {
    Map map = new HashMap<String, String>();
    // 设置队列中消息过期时间
    map.put("x-message-ttl",6000);
    return new Queue(MQQueueEnum.DIRECT_QUEUE_ORDER.getName(), true, false, false, map);
}

4.死信队列

 DLX:Dead Letter Exchange

当消息成为死信息后,会被发送达死信交换机中。

成为死信的情况:

1.队列消息长度达到限制

2.消息没被消费者消费,且不重回队列

3.消息设置了过期时间,到达了过期时间,没有被消费

 5.延时队列

TTL+死信队列构成延时队列,可用于订单过期未支付的一些业务处理

声明队列和交换机

@Bean
public Queue orderDirectQueue() {
    Map map = new HashMap<String, String>();
    // 设置队列中消息过期时间
    map.put("x-message-ttl",6000);

    // x-dead-letter-exchange    这里声明当前队列绑定的死信交换机
    map.put("x-dead-letter-exchange", "deadLetterExchange");
    // x-dead-letter-routing-key  这里声明当前队列的死信路由key
    map.put("x-dead-letter-routing-key", "dle.err");
    return new Queue(MQQueueEnum.DIRECT_QUEUE_ORDER.getName(), true, false, false, map);
}

//声明死信Exchange
@Bean
public DirectExchange deadLetterExchange(){
    return new DirectExchange("deadLetterExchange");
}

// 声明死信队列A
@Bean
public Queue deadLetterQueue(){
    return new Queue("dle-queue");
}

@Bean
public Binding deadLetterQueueBinding(Queue deadLetterQueue, DirectExchange deadLetterExchange){
    return BindingBuilder.bind(deadLetterQueue).to(deadLetterExchange).with("dle.err");
}

消费者:

​​​​​​​

/**
 * 监听死信队列
 * @param msg
 * @param channel
 * @param message
 * @throws IOException
 */
@RabbitListener(queues = "dle-queue")
public void deadLetterQueue(String msg, Channel channel, Message message) throws IOException {
    logger.info("死信队列消费消息: {}", msg);
    channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot框架可以很容易地与RabbitMQ进行集成。为了实现这个目标,你需要在项目的依赖项中添加两个关键的依赖项。首先,你需要添加spring-boot-starter-amqp依赖项,它提供了与RabbitMQ进行通信的必要类和方法。其次,你还需要添加spring-boot-starter-web依赖项,以便在项目中使用Web功能。 在你的项目中创建两个Spring Boot应用程序,一个是RabbitMQ的生产者,另一个是消费者。通过这两个应用程序,你可以实现消息的发送和接收。生产者应用程序负责将消息发送到RabbitMQ的消息队列,而消费者应用程序则负责从队列中接收并处理消息。这样,你就可以实现基于RabbitMQ的消息传递系统。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SpringBoot整合RabbitMQ](https://blog.csdn.net/K_kzj_K/article/details/106642250)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Springboot 整合RabbitMq ,用心看完这一篇就够了](https://blog.csdn.net/qq_35387940/article/details/100514134)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [undefined](undefined)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值