spring5.x-rabbitmq 基础

spring5.x-rabbitmq.png

spring-rabbitmq 此模块是从spring5x-base 基础模块扩展过来的
spring5x-base模块是一个非常干净的spring5.x+springMVC架构
如果没有搭建spring5x-base模块,请参考 spring5x-base模块搭建

搭建项目

基于spring5x-base 基础模块 新增功能:

  • 1、spring 集成RabbitMQ 及使用
  • 2、ConfirmCallback的使用及触发的一种场景
  • 3、ReturnCallback的使用及触发的一种场景

安装RabbitMQ:
RabbitMQ 介绍和安装

建议了解:RabbitMQ 图解
https://blog.csdn.net/bestmy/article/details/84304964
https://blog.csdn.net/qq_29914837/article/details/92739464
https://www.cnblogs.com/yinfengjiujian/p/9115539.html

spring5.x-rabbimq 高级篇: spring5.x-rabbimq 高级篇

1、spring 集成RabbitMQ 及使用


pom.xml

        
        
            org.springframework.amqp
            spring-rabbit
            2.1.10.RELEASE
        
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.9.8
        

注:也可以这样单独引用,spring-rabbit 内部包含了好多模块

rabbitmq.properties

#默认java连接端口
rabbitmq.addresses=localhost:5672
rabbitmq.username=guest
rabbitmq.password=guest
# 虚拟主机,等价于名称空间,默认为 / ,如果想使用其他名称空间必须先用图形界面或者管控台添加,程序不会自动创建
rabbitmq.virtual-host=/

spring-RabbitMQ.xml




    
    

    
    

    
    

    
    

    
    

    
    
    
    
    
    

    
    
        
            
            
            

            
            
            
            
        
    

    
    
        
            
            
        
    

    
    
    
    
    

    
    
        
    
    
        
    
    
        
    
    
        
    



消费者(接收消息):

Queue1Consumer.java

package com.zja.rabbitmq.consumers;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.core.MessageProperties;

import java.io.UnsupportedEncodingException;

/**
 * @author ZhengJa
 * @description 消费者1
 * @data 2019/11/4
 */
public class Queue1Consumer implements MessageListener {

    /**
     * 消费者接收消息
     * @param message 推荐使用字节
     * @return void
     */
    @Override
    public void onMessage(Message message) {
        System.out.println("进入Queue1Consumer 的监听器");

        MessageProperties m=message.getMessageProperties();
        //System.out.println("m "+m);
        String msg= null;
        try {
            //utf-8 解决 消费者接收中文消息乱码
            msg = new String (message.getBody(),"utf-8");
            System.out.println("Queue1Consumer消费掉了:  "+msg);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

Queue2Consumer.java

package com.zja.rabbitmq.consumers;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.core.MessageProperties;

import java.io.UnsupportedEncodingException;

/**
 * @author ZhengJa
 * @description 消费者2
 * @data 2019/11/4
 */
public class Queue2Consumer implements MessageListener {

    /**
     * 消费者接收消息
     * @param message 推荐使用字节
     * @return void
     */
    @Override
    public void onMessage(Message message) {
        System.out.println("进入Queue2Consumer 的监听器");
        MessageProperties m=message.getMessageProperties();
        //System.out.println("m "+m);
        String msg= null;
        try {
            //utf-8 解决 消费者接收中文消息乱码
            msg = new String (message.getBody(),"utf-8");
            System.out.println("Queue2Consumer消费掉了:  "+msg);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

RemotingConsumer.java

package com.zja.rabbitmq.consumers;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.core.MessageProperties;

import java.io.UnsupportedEncodingException;

/**
 * @author ZhengJa
 * @description 消费者
 * @data 2019/11/4
 */
public class RemotingConsumer implements MessageListener {

    /**
     * 消费者接收消息
     * @param message 推荐使用字节
     * @return void
     */
    @Override
    public void onMessage(Message message) {
        System.out.println("进入RemotingConsumer 监听器");
        MessageProperties m=message.getMessageProperties();
        //System.out.println("m "+m);
        String msg= null;
        try {
            //utf-8 解决 消费者接收中文消息乱码
            msg = new String (message.getBody(),"utf-8");
            System.out.println("RemotingConsumer消费掉了:  "+msg);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

ByteConsumer.java

package com.zja.rabbitmq.consumers;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.core.MessageProperties;

import java.io.UnsupportedEncodingException;

/**
 * @author ZhengJa
 * @description 消费者接收字节数据
 * @data 2019/11/4
 */
public class ByteConsumer implements MessageListener {

    /**
     * 消费者接收消息
     * @param message 推荐使用字节
     * @return void
     */
    @Override
    public void onMessage(Message message) {
        System.out.println("进入ByteConsumer 的监听器");

        MessageProperties m=message.getMessageProperties();

        byte[] body = message.getBody();
        try {
            System.out.println("ByteConsumer消费掉了:  "+new String(body,"utf-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

RabbitMQController.java 测试接口

package com.zja.controller;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author ZhengJa
 * @description RabbitMQ 测试
 * @data 2019/11/4
 */
@RestController
@RequestMapping("rest/rabbit")
public class RabbitMQController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @RequestMapping("/sendMsg")
    @ResponseBody
    public String sendAmqbMsg() {
        String allReceived = "我的路由键 mq.topicExchange 符合 mq.queue1、mq.queue2和mq.remoting 的要求,我应该被三个个监听器接收到";
        rabbitTemplate.convertAndSend("mq.topicExchange", "mq.queueAll.send", allReceived);
        return "success";
    }

    @RequestMapping("/sendMsg2")
    @ResponseBody
    public String sendAmqbMsg2() {
        String firstReceived = "我的路由键 mq.topicExchange 只符合 mq.queue2 的要求,只能被 mq.queue2 接收到";
        rabbitTemplate.convertAndSend("mq.topicExchange", "mq.queue2.send", firstReceived);
        return "success";
    }

    @RequestMapping("/sendMsg3")
    @ResponseBody
    public String sendAmqbMsg3() {
        String firstReceived = "我的路由键 mq.directExchange 只符合 mq.remoting 的要求,只能被 mq.remoting 接收到";
        rabbitTemplate.convertAndSend("mq.directExchange", "mq.remoting.send", firstReceived);
        return "success";
    }

    @RequestMapping("/sendMsg4")
    @ResponseBody
    public String sendAmqbMsg4() {
        String firstReceived = "我的路由键 mq.topicExchange 只符合 mq.byte 的要求,只能被 mq.byte 接收到";
        rabbitTemplate.convertAndSend("mq.topicExchange", "mq.byte.send", firstReceived);
        return "success";
    }
}

浏览器调用接口,查看控制台打印信息。

2、ConfirmCallback的使用及触发的一种场景


目前回调存在ConfirmCallback和ReturnCallback两者。他们的区别在于:

1、如果消息没有到exchange,则ConfirmCallback回调,ack=false
2、如果消息到达exchange,则ConfirmCallback回调,ack=true
3、exchange到queue成功,则不回调ReturnCallback

rabbitmq.properties

# 开启发送确认
#消息发送到交换机确认机制,是否确认回调
#如果没有本条配置信息,当消费者收到生产者发送的消息后,生产者无法收到确认成功的回调信息
rabbitmq.publisher-confirms=true

rabbitmq.properties 添加 开启回调机制

spring-RabbitMQ.xml

    
    


    
    

    
    
        
        
        
        
    
    
    
    

    
    
    

    
    
        
            
            
        
    

1、添加属性: publisher-confirms

2、注释掉之前的rabbitTemplate写法,重构并添加消息回调 confirmCallback 属性

3、添加 自定义 RabbitConfirmCallback 回调处理

RabbitConfirmCallback.java

package com.zja.rabbitmq.callback;

import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

/**
 * @author ZhengJa
 * @description 确认后回调
 * @data 2019/11/4
 */
public class RabbitConfirmCallback implements RabbitTemplate.ConfirmCallback {
    
    /**如果消息没有到exchange,则confirm回调,ack=false
     * 如果消息到达exchange,则confirm回调,ack=true
     * @param correlationData 消息唯一标识
     * @param ack 确认结果
     * @param cause 失败原因
     * @return void 
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        System.out.println("消息唯一标识:"+correlationData);
        System.out.println("确认结果:"+ack);
        System.out.println("失败原因:"+cause);
    }
}

RabbitMQController.java

package com.zja.controller;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.UnsupportedEncodingException;

/**
 * @author ZhengJa
 * @description RabbitMQ 测试
 * @data 2019/11/4
 */
@RestController
@RequestMapping("rest/rabbit")
public class RabbitMQController {

    //Spring AMQP 提供了 RabbitTemplate 来简化 RabbitMQ 发送和接收消息操作,是实现AmqpTemplate接口具有amqpTemplate功能
    @Autowired
    private RabbitTemplate rabbitTemplate;

    //测试 ConfirmCallback 失败
    @RequestMapping("/sendMsg5")
    public String sendAmqbMsg5() {
        String firstReceived = "路由键不存在 mq.NotExchange ";
        rabbitTemplate.convertAndSend("mq.NotExchange", "mq.queueAll.send", firstReceived);
        return "success";
    }
    
    //测试 ConfirmCallback 成功
    @RequestMapping("/sendMsg6")
    public String sendAmqbMsg6() {
        String firstReceived = "路由键存在 mq.topicExchange  ";
        rabbitTemplate.convertAndSend("mq.topicExchange", "mq.queueAll.send", firstReceived);
        return "success";
    }

}


失败返回返回效果:

进入 RabbitConfirmCallback:ack消息到达(true)/没有(false)到达 exchange
消息唯一标识:null
确认结果 ack:false
失败原因:channel error; protocol method: #method(reply-code=404, reply-text=NOT_FOUND - no exchange 'mq.NotExchange' in vhost '/', class-id=60, method-id=40)

成功返回效果:

进入 RabbitConfirmCallback:ack消息到达(true)/没有(false)到达 exchange
消息唯一标识:null
确认结果 ack:true
失败原因:null

3、ReturnCallback的使用及触发的一种场景


目前回调存在ConfirmCallback和ReturnCallback两者。他们的区别在于:

1、如果消息没有到exchange,则ConfirmCallback回调,ack=false
2、如果消息到达exchange,则ConfirmCallback回调,ack=true
3、exchange到queue成功,则不回调ReturnCallback

rabbitmq.properties

# 开启发送失败退回
#消息成功则不返回,启动消息失败返回:比如路由不到队列时触发回调
rabbitmq.publisher-returns=true

spring-RabbitMQ.xml

    
    

    
    

    
    

    
    
        
        
        
        
        
    
    
    
    



    
    

    
    
        
            
            
        
    

1、添加:publisher-returns 属性

2、rabbitTemplate 新增属性returnCallback、mandatory必须设置true,return callback才生效

3、添加 RabbitReturnCallback 回调后的监听器

RabbitReturnCallback.java

package com.zja.rabbitmq.callback;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

/**
 * @author ZhengJa
 * @description 失败后回调
 * @data 2019/11/4
 */
public class RabbitReturnCallback implements RabbitTemplate.ReturnCallback{
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        System.out.println(" ==== >> 进入 RabbitReturnCallback 回调 : ");
        System.out.println("消息主体 message : "+message);
        System.out.println("消息主体 message : "+replyCode);
        System.out.println("描述:"+replyText);
        System.out.println("消息使用的交换器 exchange : "+exchange);
        System.out.println("消息使用的路由键 routing : "+routingKey);
    }
}

RabbitMQController.java

package com.zja.controller;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.UnsupportedEncodingException;

/**
 * @author ZhengJa
 * @description RabbitMQ 测试
 * @data 2019/11/4
 */
@RestController
@RequestMapping("rest/rabbit")
public class RabbitMQController {

    //Spring AMQP 提供了 RabbitTemplate 来简化 RabbitMQ 发送和接收消息操作,是实现AmqpTemplate接口具有amqpTemplate功能
    @Autowired
    private RabbitTemplate rabbitTemplate;

    //测试 ReturnCallback
    @RequestMapping("/sendMsg7")
    public String sendAmqbMsg7() {
        String firstReceived = "路由键存在 mq.topicExchange 发送给 不存在的 No.mq.send 返回 ReturnCallback 并被监听到";
        rabbitTemplate.convertAndSend("mq.topicExchange", "No.mq.send", firstReceived);
        return "success";
    }
}


返回效果:

进入 RabbitReturnCallback 回调 --> exchange到queue失败
返回消息内容 : 路由键存在 mq.topicExchange 发送给 不存在的 No.mq.send 返回 ReturnCallback 并被监听到
消息回复代码 : 312
描述 : NO_ROUTE
消息使用的交换器 exchange : mq.topicExchange
消息使用的路由键 routing : No.mq.send

github 地址:

  • https://github.com/zhengjiaao/spring5x

博客地址

  • :https://www.jianshu.com/u/70d69269bd09
  • 掘金: https://juejin.im/user/5d82daeef265da03ad14881b/posts

你可能感兴趣的:(spring5.x-rabbitmq 基础)